本文通过对libextobjc 常用macro的原理讲解, 使用后, 简化了开发过程中代码, 使一些问题在编译前被发现, 减少runtime crash的发生.
libextobjc介绍
ReactiveCocoa, Carthage的作者Justin Spahr Summers, 对“hobby”项目libextobjc进行开源; libextobjc是objc的一些拓展与宏的集合, 极大地方便了objc代码的编写, 减少了关于retainCycle和内存释放的bugs;
常用macro和keywords
- @weakify 和 @strongify (ARC)
两者成对使用, 主要解决了retainCycle问题; 使用方法如下:
macro展开后的代码, 相当于注释中的简化代码;
通过两者的配合使用, 在block执行结束后, 红色线的capture就会断掉, 从而避免了retainCycle的出现;
@weakify 和 @strongify (MRC)
MRC没有weak修饰, 改成__block即可;@checkselector
iOS自带的@selector, 没有检测作用, 即使selector对应的method没有实现, 也能编译, 导致runtime crash; @checkselector通过一个魔术般神奇的代码, 实现了编译前的方法检测, 减少了crash发生. 展开后的macro如图所示:@keypath(…)
将NSObject的property属性名字转成字符串, 同时进行编译前的检测, 避免了hard coding 字符串写错的现象, 提高维护性; 展开后, 如下:
@safecategory and @synthesizeAssociation
@safecategory 避免在Category中覆盖了系统方法, 如果名字相同, category里的method会被忽略.
@synthesizeAssociation
简化在Category中添加property的步骤, 避免自定义key和使用objc_setAssocaitedObject等复杂方法, 但是不支持weak, BOOL, CGRect等property; 对下如下:
@onExit
先看一个场景:
图中为了释放methodRet, 写了3次free, 中间一旦不小心提前return, 则造成了内存泄漏;
@onExit正式为了解决这个问题; 他能保证当methodRet变量超出作用域后, 能自动执行free代码, 从而简化了代码; 相当于Swift中的defer作用; 改写的代码:
@onExit通过字符串拼接, 将block传递后变量的cleanup函数, 在变量超出作用域后, 执行这个函数(即Block). 展开后, 如下图所示:
Concrete Protocol
- 为Protocol的方法提供默认的实现
- 为已有的遵循同一个Protocol的ABC classes, 添加相同的方法;
- 使用方法
在正常的Protocol定义中使用@concrete关键字, 同时在m文件里, 对这个方法进行默认的实现;