ReactiveCocoa 中的宏
RACAnnotations
#ifndef RAC_WARN_UNUSED_RESULT
#define RAC_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#endif
RAC_WARN_UNUSED_RESULT
是在 ReactiveCocoa 框架内部声明方法时使用的宏,其旨在提示方法执行后返回的值未使用。
RACmetamacros
-
执行表达式并始终返回真
#define metamacro_exprify(...) ((__VA_ARGS__), true)
可变数量的参数都会执行,但是该宏最终都是返回一个
true
值。 -
字符串化
#define metamacro_stringify(VALUE) metamacro_stringify_(VALUE) #define metamacro_stringify_(VALUE) # VALUE
#
+VALUE
的形式会在VALUE
前后添加双引号,使其成为字符串,而若要得到NSString
对象,那么可以在该宏前面添加@
符号。 -
拼接
#define metamacro_concat(A, B) metamacro_concat_(A, B) #define metamacro_concat_(A, B) A ## B
A
+##
+B
的形式会将A
和B
展开后再拼接为一个值。 -
返回第一个参数
#define metamacro_head(...) metamacro_head_(__VA_ARGS__, 0) #define metamacro_head_(FIRST, ...) FIRST
该宏返回可变参数的第一个参数,如果没有提供参数,那么返回
0
。 -
返回指定位置的参数
#define metamacro_at0(...) metamacro_head(__VA_ARGS__) #define metamacro_at1(_0, ...) metamacro_head(__VA_ARGS__) #define metamacro_at2(_0, _1, ...) metamacro_head(__VA_ARGS__) ... #define metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) metamacro_head(__VA_ARGS__) #define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__)
metamacro_at
+N
的形式表示取参数中的第N + 1
个参数,所以在使用该系列宏时,所传递的参数个数应当至少是N + 1
个。另外,应注意这里宏的声明中的
_0, _1, _2, ... , _19
都只是形参,起到调整metamacro_head(__VA_ARGS__)
中参数个数的作用。当然,一般不会直接使用上面的宏,而是使用下面的宏
#define metamacro_at(N, ...) metamacro_concat(metamacro_at, N)(__VA_ARGS__)
使用该宏时,可变参数个数应当至少为
N + 1
个,其展开过程如下:设
N = 3, ... = a,b,c,d,e,f,g,h
,那么展开过程如下metamacro_at(3,a,b,c,d,e,f,g,h)
=>
metamacro_concat(metamacro_at, 3)(a,b,c,d,e,f,g,h)
=>
metamacro_at3(a,b,c,d,e,f,g,h)
=>
metamacro_head(d,e,f,g,h)
=>
d
所以,最后返回
d
。N 的值应当在 0~20 的范围内,包括 0 和 20 。另外,参数的索引是从 0 开始计数的。
-
返回参数个数
#define metamacro_argcount(...) \ metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
该宏运用了上面的
metamacro_at
宏,进一步则是运用了metamacro_at20
宏,从其定义可知,它的前 20 个参数实际上是无效的,最后返回的是剩余参数的第一个值。而返回的值恰好就是
__VA_ARGS__
可变参数的个数,当然,这个个数最小为 1 ,最大为 20 ,所以使用该宏计算参数个数时,要保证参数个数在 1~20 之间,包括 1 和 20 。 -
遍历参数并将其传递给宏执行
#define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ SEP \ MACRO(19, CONTEXT, _19) #define metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ SEP \ MACRO(18, CONTEXT, _18) ... #define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \ SEP \ MACRO(1, CONTEXT, _1) #define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) #define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT)
上面一系列的宏,实际是层层嵌套的,如
metamacro_foreach_cxt20
展开后包含metamacro_foreach_cxt19
+分隔 SEP
+MACRO(19, CONTEXT, _19)
,而metamacro_foreach_cxt19
继续展开为metamacro_foreach_cxt18
+分隔 SEP
+MACRO(18, CONTEXT, _18)
以此类推,直到metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0)
展开为MACRO(0, CONTEXT, _0)
为止。所以,该系列宏最终展开类似下面的形式:MACRO(0, CONTEXT, _0) SEP MACRO(1, CONTEXT, _1) SEP MACRO(2, CONTEXT, _2) SEP ... SEP MACRO(19, CONTEXT, _19)
当然,具体展开要看使用的是哪一个宏,并且
metamacro_foreach_cxt0(MACRO, SEP, CONTEXT)
表示没有参数需要传递给MACRO
进行执行,而且这里也只支持 20 个参数。同样,通常不会直接使用上面的宏,而是使用下面两个宏
#define metamacro_foreach(MACRO, SEP, ...) \ metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__) #define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \ metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
-
metamacro_foreach_cxt
宏展开过程中,其会计算可以遍历的参数个数,从而展开为对应的宏。 -
metamacro_foreach
同metamacro_foreach_cxt
类似,但是其并不会提供CONTEXT
参数给最终的宏执行,该实现是通过下面的宏:#define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG)
可见,
MACRO
只接收两个参数,一个是参数索引,另一个是参数值。
-
-
遍历参数并将其传递给宏执行
#define metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ SEP \ MACRO(19, CONTEXT, _19) #define metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ SEP \ MACRO(18, CONTEXT, _18) ... #define metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) \ SEP \ MACRO(1, CONTEXT, _1) #define metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) #define metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT)
metamacro_foreach_cxt_recursive
系列宏同metamacro_foreach_cxt
系列宏类似,都是将指定的参数传递给指定的宏,多个参数的处理结果相拼接,从而返回最终的结果。同样的,该系列宏不会直接使用,而是通过下面的宏进行使用:
#define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \ metamacro_concat(metamacro_foreach_cxt_recursive, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
这个宏同
metamacro_foreach_cxt
等同,只是如果前者若因为宏的递归扩展而出错,那么可以使用metamacro_foreach_cxt_recursive
宏进行规避。 -
拼接参数
#define metamacro_foreach_concat(BASE, SEP, ...) \ metamacro_foreach_cxt(metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__) #define metamacro_foreach_concat_iter(INDEX, BASE, ARG) metamacro_foreach_concat_iter_(BASE, ARG) #define metamacro_foreach_concat_iter_(BASE, ARG) BASE ## ARG
使用
metamacro_foreach_concat
宏,展开后的形式与下面的格式类似:BASE ## ARG1 SEP BASE ## ARG2 SEP ... SEP BASE ## ARG18 SEP BASE ## ARG19
具体最后返回什么取决于参数的个数和内容。
-
执行指定次数的宏并拼接所有的结果
#define metamacro_for_cxt20(MACRO, SEP, CONTEXT) \ metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ SEP \ MACRO(19, CONTEXT) #define metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ SEP \ MACRO(18, CONTEXT) ... #define metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT) #define metamacro_for_cxt0(MACRO, SEP, CONTEXT)
metamacro_for_cxt
系列宏同metamacro_foreach_cxt
系列宏类似,但是其并不会传递参数给要使用的宏。该系列宏不会直接使用,而是通过下面的宏进行使用。
#define metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) \ metamacro_concat(metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT)
metamacro_for_cxt
宏直接指定了执行指定宏的次数,每次执行只会传递次数索引和上下文,而没有具体的参数。
-
获取参数中除了第一个参数的剩余参数
#define metamacro_tail(...) metamacro_tail_(__VA_ARGS__) #define metamacro_tail_(FIRST, ...) __VA_ARGS__
-
获取指定个数个参数
#define metamacro_take20(...) metamacro_head(__VA_ARGS__), metamacro_take19(metamacro_tail(__VA_ARGS__)) #define metamacro_take19(...) metamacro_head(__VA_ARGS__), metamacro_take18(metamacro_tail(__VA_ARGS__)) ... #define metamacro_take1(...) metamacro_head(__VA_ARGS__) #define metamacro_take0(...)
获取指定个数个参数,返回的是一个以
,
分隔的参数列表,所以如果想直接使用,可以将其赋值给数组对象,如下:id test = @[metamacro_take2(self,self.view)];
但是,一般不直接使用上面的宏,而是使用下面的宏。
#define metamacro_take(N, ...) metamacro_concat(metamacro_take, N)(__VA_ARGS__)
如下:
id test = @[metamacro_take(2,self, self.view)];
-
移除指定个数个参数
同上面获取前
N
个参数类似,该宏可以移除前N
个参数,返回剩余参数的列表。#define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__)) #define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__)) ... #define metamacro_drop1(...) metamacro_tail(__VA_ARGS__) #define metamacro_drop0(...) __VA_ARGS__
同样,不必直接使用上面的宏,而是使用下面的宏。
#define metamacro_drop(N, ...) metamacro_concat(metamacro_drop, N)(__VA_ARGS__)
使用时,提供的参数个数应当不少于
N
。 -
减一操作
#define metamacro_dec(VAL) \ metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
对
VAL
的值进行减一操作,所以这里VAL
必须是数字,并且范围必须在 0~20 内,包括 0 和 20 。 -
增一操作
#define metamacro_inc(VAL) \ metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
对
VAL
的值进行增一操作,所以这里VAL
必须是数字,并且范围必须在 0~20 内,包括 0 和 20 。 -
判断值是否相等
#define metamacro_if_eq20(VALUE) metamacro_if_eq19(metamacro_dec(VALUE)) #define metamacro_if_eq19(VALUE) metamacro_if_eq18(metamacro_dec(VALUE)) ... #define metamacro_if_eq2(VALUE) metamacro_if_eq1(metamacro_dec(VALUE)) #define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE)) #define metamacro_if_eq0(VALUE) metamacro_concat(metamacro_if_eq0_, VALUE)
metamacro_if_eq
系列宏在使用时,层层展开,最后都是拼接为了另一个系列metamacro_if_eq0_
宏,具体为metamacro_if_eq0_ ## VALUE
,取决于VALUE
。#define metamacro_if_eq0_20(...) metamacro_expand_ #define metamacro_if_eq0_19(...) metamacro_expand_ ... #define metamacro_if_eq0_2(...) metamacro_expand_ #define metamacro_if_eq0_1(...) metamacro_expand_ #define metamacro_if_eq0_0(...) __VA_ARGS__ metamacro_consume_
可见,除了
metamacro_if_eq0_0
会替换为__VA_ARGS__ metamacro_consume_
外,其余都会替换为metamacro_expand_
。#define metamacro_consume_(...) #define metamacro_expand_(...) __VA_ARGS__
上面的宏都是为下面的这个宏服务的,其表示
A
如果和B
相等,那么其后的参数将被使用,否则下一个参数会被使用。#define metamacro_if_eq(A, B) metamacro_concat(metamacro_if_eq, A)(B)
如
metamacro_if_eq(1,1)(true)(false)
的展开过程:metamacro_if_eq(1,1)(true)(false)
=>metamacro_concat(metamacro_if_eq, 1)(1)(true)(false)
=>metamacro_if_eq1(1)(true)(false)
=>metamacro_if_eq0(metamacro_dec(1))(true)(false)
=>metamacro_if_eq0(0)(true)(false)
=>metamacro_concat(metamacro_if_eq0_, 0)(true)(false)
=>metamacro_if_eq0_0(true)(false)
=>true metamacro_consume_(false)
=>true
而
metamacro_if_eq(1,2)(true)(false)
的展开过程:metamacro_if_eq(1,2)(true)(false)
=>metamacro_concat(metamacro_if_eq, 1)(2)(true)(false)
=>metamacro_if_eq1(2)(true)(false)
=>metamacro_if_eq0(metamacro_dec(2))(true)(false)
=>metamacro_if_eq0(1)(true)(false)
=>metamacro_concat(metamacro_if_eq0_, 1)(true)(false)
=>metamacro_if_eq0_1(true)(false)
=>metamacro_expand_(false)
=>false
从展开的过程可知,
A
和B
都必须是 0~20 的数字,包括 0 和 20 ,并且B
不能小于A
。#define metamacro_if_eq_recursive(A, B) metamacro_concat(metamacro_if_eq_recursive, A)(B)
metamacro_if_eq_recursive
等同于metamacro_if_eq
,可以用于规避递归宏展开的问题。 -
判断参数是否为偶数
#define metamacro_is_even(N) \ metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
N
的值必须是 0~20 并且包括 0 和 20 。 -
参数取反
#define metamacro_not(B) metamacro_at(B, 1, 0)
参数
B
取反,其必须是 0 或 1 。
RACEXTKeyPathCoding
-
校验并返回路径
#define keypath(...) \ metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \ (keypath1(__VA_ARGS__)) \ (keypath2(__VA_ARGS__))
该宏使用
metamacro_if_eq
来判断传入的参数的个数是否是 1 ,如果是便使用keypath1
,否则使用keypath2
。#define keypath1(PATH) (((void)(NO && ((void)PATH, NO)), strchr(# PATH, '.') + 1))
这里使用了
(A,B)
语法,其中 A 和 B 都会编译执行,但是最后返回的是 B 的返回值。所以在编译过程中,会自动校验
PATH
的合法性。strchr(# PATH, '.') + 1
则是将PATH
转换为字符串,并检索第一个.
的位置,而后向后移动一位,得到去除了路径中的第一个部分的剩余路径。#define keypath2(OBJ, PATH) (((void)(NO && ((void)OBJ.PATH, NO)), # PATH))
这里在编译过程中也会去检查路径的合法性,不同的是其会直接返回
PATH
字符串。这两个宏最后返回的都是字符串,可以在其前添加
@
得到NSString
对象。NSLog(@"%@",@keypath(self.view,superview)); NSLog(@"%@",@keypath(self,view.superview)); NSLog(@"%@",@keypath(self.view.superview));
输出分别为:
superview
、view.superview
、view.superview
。宏中所包含的 void 是为了消除警告
-
校验并返回集合路径
#define collectionKeypath(...) \ metamacro_if_eq(3, metamacro_argcount(__VA_ARGS__)) \ (collectionKeypath3(__VA_ARGS__)) \ (collectionKeypath4(__VA_ARGS__))
首先,判断传递的参数是否是 3 个,如果是就使用
collectionKeypath3
宏,否则就使用collectionKeypath4
宏。#define collectionKeypath3(PATH, COLLECTION_OBJECT, COLLECTION_PATH) ([[NSString stringWithFormat:@"%s.%s",keypath(PATH), keypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String]) #define collectionKeypath4(OBJ, PATH, COLLECTION_OBJECT, COLLECTION_PATH) ([[NSString stringWithFormat:@"%s.%s",keypath(OBJ, PATH), keypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String])
这两个宏其实是对
keypath
宏的使用,如下面的例子:NSLog(@"%@",@collectionKeypath(self.array,NSArray.new,count)); NSLog(@"%@",@collectionKeypath(self,array,NSArray.new,count));
最后输出的都是:
array.count
,其实这样使用该宏,同直接使用keypath
宏没有什么区别,因为NSLog(@"%@",@keypath(self.array.count));
也输出同样的结果。该宏的设计是为了拼接集合中对象的路径,如下:
NSLog(@"%@",@collectionKeypath(self.array,Person.new,name)); NSLog(@"%@",@collectionKeypath(self,array,Person.new,name));
最后返回
array.name
。
RACEXTScope
-
原生化
#if DEBUG #define rac_keywordify autoreleasepool {} #else #define rac_keywordify try {} @catch (...) {} #endif
ReactiveCocoa 框架中定义了一个
rac_keywordify
宏,来使相关宏的使用看起来更加原生,在定义其他宏时,使用该宏,那么使用定义的宏时,便可以添加@
使这个宏看起来更加原生。 -
清理任务设置
#define onExit \ rac_keywordify \ __strong rac_cleanupBlock_t metamacro_concat(rac_exitBlock_, __LINE__) \ __attribute__((cleanup(rac_executeCleanupBlock), unused)) = ^
使用
onExit
宏,可以很方便的为当前代码域添加处理任务。如下面的方法:
- (void)test { NSLog(@"test start"); @onExit { NSLog(@"test end"); }; }
当在调试模式下时,其展开如下:
- (void)test { NSLog(@"test start"); @autoreleasepool {} __strong rac_cleanupBlock_t metamacro_concat(rac_exitBlock_, __LINE__) __attribute__((cleanup(rac_executeCleanupBlock), unused)) = ^{ NSLog(@"test end"); }; }
假设代码所处行号为 50 ,即
__LINE__
为 50 ,那么进一步展开。- (void)test { NSLog(@"test start"); @autoreleasepool {} __strong rac_cleanupBlock_t rac_exitBlock_50 __attribute__((cleanup(rac_executeCleanupBlock), unused)) = ^{ NSLog(@"test end"); }; }
那么可知,
onExit
宏,最终展开后,就是声明了一个rac_cleanupBlock_t
类型的变量并初始化,且使用了__attribute__
字段指明在其作用域结束时,将其传递给指定的清理函数rac_executeCleanupBlock
。typedef void (^rac_cleanupBlock_t)(void); static inline void rac_executeCleanupBlock (__strong rac_cleanupBlock_t *block) { (*block)(); }
-
弱引用变量和强引用变量
在 ReactiveCocoa 框架中,定义了两个宏,用来弱化和强化变量,从而防止循环引用问题。
-
声明弱引用变量
#define weakify(...) \ rac_keywordify \ metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__) #define unsafeify(...) \ rac_keywordify \ metamacro_foreach_cxt(rac_weakify_,, __unsafe_unretained, __VA_ARGS__) #define rac_weakify_(INDEX, CONTEXT, VAR) \ CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
这里提供了两个宏,
unsafeify
用来弱化不支持的__weak
字段的变量,会使用__unsafe_unretained
代替__weak
字段修饰声明的变量。如在调试模式下,弱化
self
和UIView *view = self.view;
的过程:@weakify(self,view) => @autoreleasepool {} metamacro_foreach_cxt(rac_weakify_,, __weak, self, view) => @autoreleasepool {} metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(self, view))(rac_weakify_,, __weak, self, view) => metamacro_foreach_cxt2(rac_weakify_,, __weak, self, view) => metamacro_foreach_cxt1(rac_weakify_,,__weak, self) rac_weakify_(1, __weak, view) => rac_weakify_(0, __weak, self) __weak __typeof__(view) metamacro_concat(view, _weak_) = (view); => __weak __typeof__(self) metamacro_concat(self, _weak_) = (self); __weak __typeof__(view) view_weak_ = (view); => __weak __typeof__(self) self_weak_ = (self); __weak __typeof__(view) view_weak_ = (view);
可知,
@weakify(self,view)
展开后的结果为__weak __typeof__(self) self_weak_ = (self); __weak __typeof__(view) view_weak_ = (view);
即声明了两个弱引用变量
self_weak
和view_weak_
,从这里也可知该宏的参数不能是包含的.
的表达式,如self.view
,否则,最后展开的变量为self.view_weak
显然是错误的。 -
声明强引用
#define strongify(...) \ rac_keywordify \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wshadow\"") \ metamacro_foreach(rac_strongify_,, __VA_ARGS__) \ _Pragma("clang diagnostic pop") #define rac_strongify_(INDEX, VAR) \ __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);
该宏必须要和上面的弱引用宏配对使用,如
@strongify(self,view)
的展开@strongify(self,view) => metamacro_foreach(rac_strongify_,, self,view) => metamacro_foreach_cxt(metamacro_foreach_iter,, rac_strongify_, self, view) => metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(self, view)) (metamacro_foreach_iter,, rac_strongify_, self, view) => metamacro_foreach_cxt2(metamacro_foreach_iter,, rac_strongify_, self, view) => metamacro_foreach_cxt1(metamacro_foreach_iter,, rac_strongify_, self) metamacro_foreach_iter(1, rac_strongify_, view) => metamacro_foreach_iter(0, rac_strongify_, self) rac_strongify_(1, view) => rac_strongify_(0, self) __strong __typeof__(view) view = metamacro_concat(view, _weak_); => __strong __typeof__(self) self = metamacro_concat(self, _weak_); __strong __typeof__(view) view = view_weak_; => __strong __typeof__(self) self = self_weak_; __strong __typeof__(view) view = view_weak_;
最后展开结果为
__strong __typeof__(self) self = self_weak_;__strong __typeof__(view) view = view_weak_;
但是,这里可以看到存在对 self 和 view 的重复定义,所以两者不能在一个作用域内,并且应使用
_Pragma
消除命名重复警告。所以综上可知,
- (void)test { UIView *view = self.view; @weakify(self,view) @onExit { @strongify(self,view) }; }
展开后为
- (void)test { UIView *view = self.view; __weak __typeof__(self) self_weak_ = (self); __weak __typeof__(view) view_weak_ = (view); @autoreleasepool {} __strong rac_cleanupBlock_t rac_exitBlock_50 __attribute__((cleanup(rac_executeCleanupBlock), unused)) = ^{ _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\"") __strong __typeof__(self) self = self_weak_; __strong __typeof__(view) view = view_weak_; _Pragma("clang diagnostic pop") }; }
-
关于宏的基本概念和用法可以参考OneV’s Den 的文章