到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf

本文探讨Objective-C中Block的内存管理技巧,特别是如何避免循环引用(retain cycle),介绍使用weak和strong关键字来管理Block内的self引用,确保程序稳定运行。

原文作者: lslin

原文链接: http://blog.lessfun.com/blog/2014/11/22/when-should-use-weakself-and-strongself-in-objc-block/


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
2
3
4
__weak __typeof__(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [weakSelf doSomething];
});

clang 的文档表示,在 doSomething 内,weakSelf 不会被释放。但,下面的情况除外:

1
2
3
4
5
__weak __typeof__(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [weakSelf doSomething];
    [weakSelf doOtherThing];
});

在 doSomething 中,weakSelf 不会变成 nil,不过在 doSomething 执行完成,调用第二个方法 doOtherThing 的时候,weakSelf 有可能被释放,于是,strongSelf 就派上用场了:

1
2
3
4
5
6
__weak __typeof__(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    __strong __typeof(self) strongSelf = weakSelf;
    [strongSelf doSomething];
    [strongSelf doOtherThing];
});

__strong 确保在 Block 内,strongSelf 不会被释放。

总结

  • 在 Block 内如果需要访问 self 的方法、变量,建议使用 weakSelf。
  • 如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。

参考


在 iOS 开发中,当使用嵌套的 Block 时,是否需要对内部 Block 进行强引用以避免内存问题,取决于具体的使用场景和上下文环境。 Block 本质上是一种带有自动内存管理的对象,它们在栈上创建,通常会被复制到堆上以延长生命周期。当 Block 被赋值给一个使用 `strong` 修饰符声明的属性或变量时,它会保持对捕获变量的强引用。如果 Block 捕获了某个对象(例如 `self`),而该对象又持有这个 Block,就会形成循环引用(retain cycle),从而导致内存泄漏。 在嵌套 Block 的情况下,外层 Block 持有内层 Block 的强引用,因为通常会将其赋值给一个 `strong` 属性或局部变量。如果内部 Block 不需要被外部强引用(例如它仅在外部 Block 的作用域内执行),则不需要额外的强引用。但如果内部 Block 需要在外部作用域中被访问或延迟执行,则应确保其被适当地强引用。 为了避免在嵌套 Block 中出现循环引用问题,通常建议使用 `__weak` 来弱化对 `self` 的引用,以打破强引用链。例如: ```objc __weak typeof(self) weakSelf = self; self.blockA = ^{ __strong typeof(weakSelf) strongSelf = weakSelf; if (strongSelf) { strongSelf.blockB = ^{ [strongSelf doSomething]; }; } }; ``` 上述代码中,外层 Block 使用 `__weak` 来避免对 `self` 的强引用,防止循环引用。而在 Block 内部,使用 `__strong` 将 `weakSelf` 转换为 `strongSelf`,确保在 Block 执行期间 `self` 不会被释放。对于嵌套的 `blockB`,同样适用此模式,以确保在执行时 `self` 仍然有效[^4]。 此外,在使用第三方宏(如 `@weakify` 和 `@strongify`)时,这些宏通常会自动处理弱引用和强引用的转换,简化了手动管理引用的过程。 总结: - 如果内部 Block 仅在外部 Block 内部使用且不被外部保留,则不需要额外的强引用。 - 如果内部 Block 需要被外部保留或延迟执行,则应确保其被强引用。 - 为避免循环引用,建议在 Block 内部使用 `__weak` 和 `__strong` 配合使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值