理解@weakify 宏
Understanding @weakify macro
@weakify 在幕后是如何工作的?使用 @weakify(self) 的想法是让它作为一个 shorthand 到这个:
__weak __typeof__(self) weakSelf = self;
注意:@weakify 宏被定义为here.
我试图通过收集它使用的所有宏来了解它是如何工作的:
#define weakify(...) \
ext_keywordify \
metamacro_foreach_cxt(ext_weakify_,, __weak, __VA_ARGS__)
#define ext_weakify_(INDEX, CONTEXT, VAR) \
CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
#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)
#define metamacro_concat(A, B) \
metamacro_concat_(A, B)
#define metamacro_concat_(A, B) A ## B
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
#define metamacro_at(N, ...) \
metamacro_concat(metamacro_at, N)(__VA_ARGS__)
#define metamacro_head(...) \
metamacro_head_(__VA_ARGS__, 0)
#define metamacro_head_(FIRST, ...) FIRST
#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_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) 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__)
#if DEBUG
#define ext_keywordify autoreleasepool {}
#else
#define ext_keywordify try {} @catch (...) {}
#endif
我将上面和下面的整个代码放入一个 .c 文件中:
@weakify(self)
并使用 gcc -E test.c.
编译它
我得到的输出是:
@try {} @catch (...) {} __attribute__((objc_gc(weak))) __typeof__(self) self_weak_ = (self);
问题:
鉴于宏生成的输出是 self_weak_。在使用@weakify(self)的普通代码中,调用weakify()后仍然直接引用self,如何使用self变成一个鉴于代码不使用 self_weak_?
例如,我经常看到这个:
@weakify(self)
[[self.obj doSomething];
self.obj如何使用weak self?代码不应该是:
@weakify(self)
[[self_weak_.obj doSomething];
如果使用
转储 clang 预定义宏
clang -dM -E -x c /dev/null
然后你会发现
#define __weak __attribute__((objc_gc(weak)))
因此,如果您在源代码中写入 __weak
,这将扩展为
clang 属性 objc_gc(weak)
。也就是说,
@try {} @catch (...) {} __attribute__((objc_gc(weak))) __typeof__(self) self_weak_ = (self);
等同于
@try {} @catch (...) {} __weak __typeof__(self) self_weak_ = (self);
现在 @try {} @catch (...) {}
是一个空操作(定义一个
出现以@
字符开头的宏,比较How can I use commercial at sign in Objective-C macro?),
所以剩下的是
__weak __typeof__(self) self_weak_ = (self);
这是定义和初始化弱变量 self_weak_
指向与 self
指向的相同对象的标准。
@weakify
应与对应的 @strongify
一起使用,
例如:
@weakify(self);
// Expands to:
// __weak __typeof__(self) self_weak_ = (self);
void (^someClosure)(void) = ^void () {
@strongify(self);
// Expands to:
// __strong __typeof__(self) self = (self_weak_);
if (self) {
[self doSomething];
[self doSomethingElse];
}
};
在闭包内部,self
是一个 local 变量并初始化为
如果该对象仍然存在,则对该对象的强引用。
如果对象已被释放(因为没有强
对它的引用已经存在),self_weak_
是 nil
并且局部变量
self
也是 nil
.
@weakify 在幕后是如何工作的?使用 @weakify(self) 的想法是让它作为一个 shorthand 到这个:
__weak __typeof__(self) weakSelf = self;
注意:@weakify 宏被定义为here.
我试图通过收集它使用的所有宏来了解它是如何工作的:
#define weakify(...) \
ext_keywordify \
metamacro_foreach_cxt(ext_weakify_,, __weak, __VA_ARGS__)
#define ext_weakify_(INDEX, CONTEXT, VAR) \
CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
#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)
#define metamacro_concat(A, B) \
metamacro_concat_(A, B)
#define metamacro_concat_(A, B) A ## B
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
#define metamacro_at(N, ...) \
metamacro_concat(metamacro_at, N)(__VA_ARGS__)
#define metamacro_head(...) \
metamacro_head_(__VA_ARGS__, 0)
#define metamacro_head_(FIRST, ...) FIRST
#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_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) 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__)
#if DEBUG
#define ext_keywordify autoreleasepool {}
#else
#define ext_keywordify try {} @catch (...) {}
#endif
我将上面和下面的整个代码放入一个 .c 文件中:
@weakify(self)
并使用 gcc -E test.c.
编译它我得到的输出是:
@try {} @catch (...) {} __attribute__((objc_gc(weak))) __typeof__(self) self_weak_ = (self);
问题:
鉴于宏生成的输出是 self_weak_。在使用@weakify(self)的普通代码中,调用weakify()后仍然直接引用self,如何使用self变成一个鉴于代码不使用 self_weak_?
例如,我经常看到这个:
@weakify(self)
[[self.obj doSomething];
self.obj如何使用weak self?代码不应该是:
@weakify(self)
[[self_weak_.obj doSomething];
如果使用
转储 clang 预定义宏clang -dM -E -x c /dev/null
然后你会发现
#define __weak __attribute__((objc_gc(weak)))
因此,如果您在源代码中写入 __weak
,这将扩展为
clang 属性 objc_gc(weak)
。也就是说,
@try {} @catch (...) {} __attribute__((objc_gc(weak))) __typeof__(self) self_weak_ = (self);
等同于
@try {} @catch (...) {} __weak __typeof__(self) self_weak_ = (self);
现在 @try {} @catch (...) {}
是一个空操作(定义一个
出现以@
字符开头的宏,比较How can I use commercial at sign in Objective-C macro?),
所以剩下的是
__weak __typeof__(self) self_weak_ = (self);
这是定义和初始化弱变量 self_weak_
指向与 self
指向的相同对象的标准。
@weakify
应与对应的 @strongify
一起使用,
例如:
@weakify(self);
// Expands to:
// __weak __typeof__(self) self_weak_ = (self);
void (^someClosure)(void) = ^void () {
@strongify(self);
// Expands to:
// __strong __typeof__(self) self = (self_weak_);
if (self) {
[self doSomething];
[self doSomethingElse];
}
};
在闭包内部,self
是一个 local 变量并初始化为
如果该对象仍然存在,则对该对象的强引用。
如果对象已被释放(因为没有强
对它的引用已经存在),self_weak_
是 nil
并且局部变量
self
也是 nil
.