@weakify 和 @strongify 是 RAC 中對于強(qiáng)弱引用操作的宏定義。
1. 拆解宏定義
下面的代碼以 self 作為例子,也就是說,括號中也可以是其他對象。
// @weakify(self) 實(shí)際上被宏定義為:
#define weakify(...) \
ext_keywordify \
metamacro_foreach_cxt(ext_weakify_,, __weak, __VA_ARGS__)
// 經(jīng)過拆解,最終實(shí)際上是這樣:
autoreleasepool {}__weak __typeof__(self) self_weak_ = self
@weakify 相當(dāng)于定義了一個(gè) _weak 弱引用,self 類型的指針變量 self_weak,指向 self 的值。
// @strongify(self)實(shí)際上被宏定義為:
#define strongify(...) \
ext_keywordify \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
metamacro_foreach(ext_strongify_,, __VA_ARGS__) \
_Pragma("clang diagnostic pop")
// 經(jīng)過拆解,最終實(shí)際上是這樣:
autoreleasepool {}__typeof__(self) self = self_weak_;
而 @strongify 相當(dāng)于定義了一個(gè)名為 self 的變量,指向 self_weak_ 所指向的值。同時(shí),抑制了同名錯(cuò)誤,作用會(huì)在下文詳解。
2. 內(nèi)存管理
考慮如下例子:
void useWeakifyStrongify() {
@weakify(self);
self.someBlock = ^ {
@strongify(self);
NSLog(@"%@", self);
}
}
2.1 代碼執(zhí)行前
在對象創(chuàng)建之時(shí),self 指針就強(qiáng)引用了 self obj 對象。

2.2 代碼執(zhí)行 @weakify(self):
結(jié)合上文拆解的宏定義,@weakify 操作定義了一個(gè)名為 self_weak_ 的變量,弱引用 self obj。

2.3 代碼執(zhí)行 @strongify(self):
@strongify 做了如下操作:在 block 的作用域里,創(chuàng)建了一個(gè)局部變量,名稱為 self,覆蓋了外部的 self 變量。由于在宏定義中抑制了 "warn whenever a local variable shadows another local variable." 錯(cuò)誤,所以編譯器不會(huì)報(bào)重名錯(cuò)誤。這樣做的好處是我們?nèi)匀豢梢栽?block 中使用 self 作為變量名,不需要額外定義變量。
其實(shí) block 可以表示成直接引用 self obj,這里為了表明邏輯關(guān)系,先經(jīng)過了 self(local) ,然后間接的指向了 self obj。

2.4 嵌套情況
對于嵌套使用 block 的情況,則需要多次插入 @strongify 來避免循環(huán)引用:
void nestedBlocksStrongify() {
@weakify(self);
self.someBlock = ^ { // outside block
@strongify(self);
self.anotherBlock = ^{ // inside block
@strongify(self);
NSLog(@"%@", self);
};
};
}
3. 總結(jié)
可以看到,RAC 的設(shè)計(jì)者通過使用 @strongify 和 @weakify 后,達(dá)到了以下三點(diǎn):
- 避免循環(huán)引用。上圖中不存在環(huán)。
- 避免當(dāng)弱指針指向 self obj 時(shí),self obj 被其他操作釋放后,成為野指針的問題。因?yàn)樵?local 作用域中始終有個(gè)強(qiáng)指針指向 self obj。
- 避免新建變量名。傳統(tǒng)的 __weak 方法解決循環(huán)引用時(shí),需要定義新的變量來保存 self obj 的若指針。但是使用 @strongify 后,在 local 作用域中定義了一個(gè)同名的 self 變量,所以不需要額外定義新的變量,直接用 self 就可以使用 self。