首先要说说什么时候使用weakSelf和strongSelf。
下面引用一篇博客《到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf》的内容:
Objective C 的 Block
是一个很实用的语法,特别是与GCD结合使用,可以很方便地实现并发、异步任务。但是,如果使用不当,Block 也会引起一些循环引用问题(retain cycle
)—— Block 会 retain ‘self’,而 ‘self‘ 又 retain 了 Block。因为在 ObjC 中,直接调用一个实例变量,会被编译器处理成 ‘self->theVar’,’self’ 是一个 strong 类型的变量,引用计数会加 1,于是,self retains queue, queue retains block,block retains self。
解决 retain circle
Apple 官方的建议是,传进 Block 之前,把 ‘self’ 转换成 weak automatic 的变量,这样在 Block 中就不会出现对 self 的强引用。如果在 Block 执行完成之前,self 被释放了,weakSelf 也会变为 nil。
示例代码:
1 __weak __typeof__(self) weakSelf = self; 2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 3 [weakSelf doSomething]; 4 });
clang 的文档表示,在 doSomething 内,weakSelf 不会被释放。但,下面的情况除外:
1 __weak __typeof__(self) weakSelf = self; 2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 3 [weakSelf doSomething]; 4 [weakSelf doOtherThing]; 5 });
在 doSomething 中,weakSelf 不会变成 nil,不过在 doSomething 执行完成,调用第二个方法 doOtherThing 的时候,weakSelf 有可能被释放,于是,strongSelf 就派上用场了:
1 __weak __typeof__(self) weakSelf = self; 2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 3 __strong __typeof(self) strongSelf = weakSelf; 4 [strongSelf doSomething]; 5 [strongSelf doOtherThing]; 6 });
__strong
确保在 Block 内,strongSelf 不会被释放。
总结
- 在 Block 内如果需要访问 self 的方法、变量,建议使用 weakSelf。
- 如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。
-------------------------------分割线---------------------------------------------
以上内容知道了我们为什么要用weakSelf和strongSelf, 为了简单实用一般会定义成宏weakify和strongify,如下:

1 #ifndef weakify 2 #if __has_feature(objc_arc) 3 4 #define weakify( x ) \ 5 _Pragma("clang diagnostic push") \ 6 _Pragma("clang diagnostic ignored \"-Wshadow\"") \ 7 autoreleasepool{} __weak __typeof__(x) __weak_##x##__ = x; \ 8 _Pragma("clang diagnostic pop") 9 10 #else 11 12 #define weakify( x ) \ 13 _Pragma("clang diagnostic push") \ 14 _Pragma("clang diagnostic ignored \"-Wshadow\"") \ 15 autoreleasepool{} __block __typeof__(x) __block_##x##__ = x; \ 16 _Pragma("clang diagnostic pop") 17 18 #endif 19 #endif 20 21 #ifndef strongify 22 #if __has_feature(objc_arc) 23 24 #define strongify( x ) \ 25 _Pragma("clang diagnostic push") \ 26 _Pragma("clang diagnostic ignored \"-Wshadow\"") \ 27 try{} @finally{} __typeof__(x) x = __weak_##x##__; \ 28 _Pragma("clang diagnostic pop") 29 30 #else 31 32 #define strongify( x ) \ 33 _Pragma("clang diagnostic push") \ 34 _Pragma("clang diagnostic ignored \"-Wshadow\"") \ 35 try{} @finally{} __typeof__(x) x = __block_##x##__; \ 36 _Pragma("clang diagnostic pop") 37 38 #endif 39 #endif
使用过RAC的同学应该都知道@weakify和@strongify,这两个宏在RAC中是已经定义好的,可以直接用,属于比较牛逼的写法。这两个宏一定成对出现,先@weakify再@strongify.可以很好的管理Block内部对self的引用。可以一步步点开发现其实使用到了C语言中的组合运算符。
1 @weakify(self); 2 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 3 @strongify(self); 4 [self doSomething]; 5 [self doOtherThing]; 6 });
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库