5.0.0版本需求对小铅笔进行了整体页面修改,我调整了页面的布局,并实现了一套适配iPad的方案,方案就是把图片,文字,间距,圆角等都按设计稿的比例进行了放大。
效果还不错(大佬说这效果就像老人机:D),就是方法比较笨,需要在每个约束的地方和字体大小的设置给一个转换后的值。
_coverBgView.layer.cornerRadius = SPACE(4);
_nameLabel.font = TP_GLOBAL_FONT_SIZE(SPACE(14));
[self.cornerRadiusView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self);
make.leading.mas_equalTo(self).mas_offset(SPACE(10));
make.trailing.mas_equalTo(self).mas_offset(SPACE(-10));
make.height.mas_equalTo(SPACE(20));
}];
这里的值转换我用了宏来写,第一版是这样
#define SPACE(i) (i*[UIScreen mainScreen].bounds.size.width*1.0/375)
后来觉得在手机上不需要按照比例调整,只在iPad上启动这种模式就好了,改成了这样
#define SPACE(i) (IS_IPAD ? i*[UIScreen mainScreen].bounds.size.width*1.0/375 : i)
然后问题就来了,作品栏跟角色栏的高度相差的就是红色框框的35pt的tab控件,但是效果是作品栏矮了很多。
乍看代码好像也没问题
self.roleCellSize = CGSizeMake(screenWidth, roleCellHeight + SPACE(45));
self.productCellSize = CGSizeMake(screenWidth, roleCellHeight + SPACE(45+35));
把值打印后发现,SPACE(45)值为122.88,SPACE(45+35)值为140.573,80*1024/375=218.453才是正确的答案,为什么在宏里就算不对?
宏(Macro),是一种批量处理的称谓。计算机科学里的宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式。
百度一下宏定义得知,它是一种替换。
#define SPACE(i) (IS_IPAD ? i*[UIScreen mainScreen].bounds.size.width*1.0/375 : i)
SPACE(45+35),就是等于45+3510241.0/375,所以根据加减乘除的优先级运算,并没有得出理想中的结果。然后我就把能加上括号的地方都加上了括号,
#define SPACE(i) (IS_IPAD ? ((i)*[UIScreen mainScreen].bounds.size.width*1.0/375) : i)
这样子,无论是SPACE(45+35)还是SPACE(45+35)*35,结果都是正确的。
下面学习一下系统的取两数中较小值的宏MIN(A,B)
#define __NSX_PASTE__(A,B) A##B
#if !defined(MIN)
#define __NSMIN_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__a,L) : __NSX_PASTE__(__b,L); })
#define MIN(A,B) __NSMIN_IMPL__(A,B,__COUNTER__)
#endif
逐步来看一下这个宏,先解释三个比较陌生的地方。
1、 __COUNTER__是一个计数器,从0开始计数,每次调用加1,这里就是当做是一个通常配合##使用,用于构建唯一的标识符。
#define __NSX_PASTE__(A,B) A##B
这里的这个宏利用外部传入的参数与__COUNTER__连接,生成一个唯一的标识。
2、##是一个连接符,它的效果如下
#define AA(a, b) a##b
NSLog(@"%@", [AA(NS, String) stringWithFormat:@"aa"]);
NSLog(@"%d", AA(10, 0));
打印结果为
3、这一段看起来像是对传入的参数A进行了一个处理,
__typeof__(A) __NSX_PASTE__(__a,L) = (A);
刚才有说__NSX_PASTE__(__a,L),就是形成了一个唯一标识,我们把这个标识当成是x。
__typeof__(A) x = (A);
typeof在这里的意思是把x定义成A指向的数据类型,这样就声明一个同样数据类型的参数x来保存A的原始值,这样做是为了保证2和1++比较的正确性。
感受一下typeof的效果,声明两个宏一个有typeof,一个没有,
#define MINI(A,B) (A < B ? A : B)
#define MINII(A,B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; })
int a = 1; int b = 1;
NSLog(@"%d %d", MINI(2, a++), MINII(2, b++));
调用,打印结果
如果取2跟1++的最小值,正确结果应该是1。因为前者因为1++在三目运算里又自加了一次,导致答案错了,如果这发生在更加复杂的运算,就更影响运算的结果了。
4、
最后我们就可以很轻松得解读这个宏,利用了计数器连接,生成了两个唯一标识的参数,参数的值为传参的原始值,再用两个参数来比较得出了最小值。