weakify
源码:
#define weakify(...) \
autoreleasepool {} \
metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)
使用方法:
@weakify(anObject);
//展开后
@autoreleasepool{
}
metamacro_foreach_cxt(rac_weakify_,,__weak,__VA_ARGS__)
这里有两个问题:
- autoreleasepool的作用是什么?
- metamacro_foreach_cxt干了什么 ?
在使用这两个宏时,为了看起来符合libextobjc的语言习惯,前面会加上@,所以autoreleasepool仅仅是为了配合使用宏的是@符号。
再看后者:
/**
* 对于每个参数,使用MACRO进行处理,然后使用SEP分隔
*/
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
其中:
metamacro_concat(A,B) \\拼接A,B两个字符串
metamacro_argcount(...) \\返回参数的个数
所以展开后:
@weakify(anObject);
//展开后
@autoreleasepool{
}
metamacro_foreach_cxt1(rac_weakify_,,__weak,__VA_ARGS__)
//继续展开
@autoreleasepool{
}
rac_weakify(0,__weak, anObject)
//rac_weakify展开后
@autoreleasepool{
}
__weak __typeof__(anObject) anObject_weak_ = (anObject)
所以最终weakify定义了一个object_weak_变量,以weak方式引用object。
同样展开strongtify宏之后,其结果是:
__strong __typeof__(anObject) anObject = anObject_weak_
所以是在block中将定义了一个局部变量object指向了object_weak_
RACObserve
定义:
#define RACObserve(TARGET, KEYPATH) \
[(id)(TARGET) rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]
这里看主要是调用了rac_valuesForKeyPath方法,而这个方法的参数使用了另一个宏keypath。
#define keypath(...) \
metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(keypath1(__VA_ARGS__))(keypath2(__VA_ARGS__))
#define keypath1(PATH) \
(((void)(NO && ((void)PATH, NO)), strchr(# PATH, '.') + 1))
#define keypath2(OBJ, PATH) \
(((void)(NO && ((void)OBJ.PATH, NO)), # PATH))
metamacro_if_eq的作用就是如果参数数量等于1,就执行keypath1,否则执行keypath2(其实这里metamacro_if_eq的实现方式也值得看一下)。自动提示就是通过OBJ.PATH来做的,keypath2返回的其实就是PATH的字符串形式。
网友评论