iOS中block的详解weakSelf、strongSelf <转自唐巧>

1

我们知道,在使用 block 的时候,为了避免产生循环引用,通常需要使用 weakSelf 与 strongSelf,写下面这样的代码:

__weak typeof(self) weakSelf = self;
[self doSomeBlockJob:^{
    __strong typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        ...
    }
}];

那么请问:什么时候在 block 里面用 self,不需要使用 weak self?

答案

当 block 本身不被 self 持有,而被别的对象持有,同时不产生循环引用的时候,就不需要使用 weak self 了。最常见的代码就是 UIView 的动画代码,我们在使用 UIView 的 animateWithDuration:animations 方法 做动画的时候,并不需要使用 weak self,因为引用持有关系是:

UIView 的某个负责动画的对象持有了 block
block 持有了 self
因为 self 并不持有 block,所以就没有循环引用产生,因为就不需要使用 weak self 了。

[UIView animateWithDuration:0.2 animations:^{
    self.alpha = 1;
}];

当动画结束时,UIView 会结束持有这个 block,如果没有别的对象持有 block 的话,block 对象就会释放掉,从而 block 会释放掉对于 self 的持有。整个内存引用关系被解除。

思考题

如果觉得上面的问题太简单,可以想想下面两个题目:

为什么 block 里面还需要写一个 strong self,如果不写会怎么样?
有没有这样一个需求场景,block会产生循环引用,但是业务又需要你不能使用 weak self? 如果有,请举一个例子并且解释这种情况下如何解决循环引用问题。

2

继续回答昨天的问题第二问。

我们知道,在使用 block 的时候,为了避免产生循环引用,通常需要使用 weakSelf 与 strongSelf,写下面这样的代码:

__weak typeof(self) weakSelf = self;
[self doSomeBackgroundJob:^{
    __strong typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf) {
        ...
    }
}];

那么请问:为什么 block 里面还需要写一个 strong self,如果不写会怎么样?

答案

在 block 中先写一个 strong self,其实是为了避免在 block 的执行过程中,突然出现 self 被释放的尴尬情况。通常情况下,如果不这么做的话,还是很容易出现一些奇怪的逻辑,甚至闪退。

我们以 AFNetworking 中 AFNetworkReachabilityManager.m 的一段代码举例:

__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
    __strong __typeof(weakSelf)strongSelf = weakSelf;

    strongSelf.networkReachabilityStatus = status;
    if (strongSelf.networkReachabilityStatusBlock) {
        strongSelf.networkReachabilityStatusBlock(status);
    }

};

如果没有 strongSelf 的那行代码,那么后面的每一行代码执行时,self 都可能被释放掉了,这样很可能造成逻辑异常。

特别是当我们正在执行 strongSelf.networkReachabilityStatusBlock(status); 这个 block 闭包时,如果这个 block 执行到一半时 self 释放,那么多半情况下会 Crash。

这里有一篇文章详细解释了这个问题:https://dhoerl.wordpress.com/2013/04/23/i-finally-figured-out-weakself-and-strongself/

另外,还有读者提了两个有意思的问题,大家可以思考一下:

提问:“数组” 和 “字典” 的 enumeratXXXUsingBlock: 是否要使用 weakSelf 和 strongSelf 呢?

提问:block 里 strong self 后,block 不是也会持有 self 吗?而 self 又持有 block ,那不是又循环引用了?

3

有没有这样一个需求场景,block 会产生循环引用,但是业务又需要你不能使用 weak self? 如果有,请举一个例子并且解释这种情况下如何解决循环引用问题。

答案

需要不使用 weak self 的场景是:你需要构造一个循环引用,以便保证引用双方都存在。比如你有一个后台的任务,希望任务执行完后,通知另外一个实例。在我们开源的 YTKNetwork 网络库的源码中,就有这样的场景。

在 YTKNetwork 库中,我们的每一个网络请求 API 会持有回调的 block,回调的 block 会持有 self,而如果 self 也持有网络请求 API 的话,我们就构造了一个循环引用。虽然我们构造出了循环引用,但是因为在网络请求结束时,网络请求 API 会主动释放对 block 的持有,因此,整个循环链条被解开,循环引用就被打破了,所以不会有内存泄漏问题。代码其实很简单,如下所示:

- (void)clearCompletionBlock {
    // nil out to break the retain cycle.
    self.successCompletionBlock = nil;
    self.failureCompletionBlock = nil;
}

总结来说,解决循环引用问题主要有两个办法:

第一个办法是「事前避免」,我们在会产生循环引用的地方使用 weak 弱引用,以避免产生循环引用。
第二个办法是「事后补救」,我们明确知道会存在循环引用,但是我们在合理的位置主动断开环中的一个引用,使得对象得以回收。
思考题

下期的问题是:weak 变量在引用计数为 0 时,会被自动设置成 nil,这个特性是如何实现的?

4

weak 变量在引用计数为0时,会被自动设置成 nil,这个特性是如何实现的?

答案

在 Friday QA 上,有一期专门介绍 weak 的实现原理。https://mikeash.com/pyblog/friday-qa-2010-07-16-zeroing-weak-references-in-objective-c.html

《Objective-C高级编程》一书中也介绍了相关的内容。

简单来说,系统有一个全局的 CFMutableDictionary 实例,来保存每个对象的 weak 指针列表,因为每个对象可能有多个 weak 指针,所以这个实例的值是 CFMutableSet 类型。

剩下我们要做的,就是在引用计数变成 0 的时候,去这个全局的字典里面,找到所有的 weak 指针,将其值设置成 nil。如何做到这一点呢?Friday QA 上介绍了一种类似 KVO 实现的方式。当对象存在 weak 指针时,我们可以将这个实例指向一个新创建的子类,然后修改这个子类的 release 方法,在 release 方法中,去从全局的 CFMutableDictionary 字典中找到所有的 weak 对象,并且设置成 nil。我摘抄了 Friday QA 上的实现的核心代码,如下:

Class subclass = objc_allocateClassPair(class, newNameC, 0);
Method release = class_getInstanceMethod(class, @selector(release));
Method dealloc = class_getInstanceMethod(class, @selector(dealloc));
class_addMethod(subclass, @selector(release), (IMP)CustomSubclassRelease, method_getTypeEncoding(release));
class_addMethod(subclass, @selector(dealloc), (IMP)CustomSubclassDealloc, method_getTypeEncoding(dealloc));
objc_registerClassPair(subclass);

当然,这并不代表苹果官方是这么实现的,因为苹果的这部分代码并没有开源。《Objective-C高级编程》一书中介绍了 GNUStep 项目中的开源代码,思想也是类似的。所以我认为虽然实现细节会有差异,但是大致的实现思路应该差别不大。

全文完。

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是一些优秀的Android Framework博客: 1. Android Developers Blog:由Google官方提供的博客,涵盖了各种Android Framework的最新消息和特性介绍。 2. Mindorks:提供许多高质量的Android开发教程和文章,包括Android Framework的深入讲解。 3. CodePath Android Cliffnotes:提供了详细的Android Framework教程,包括Activity、Fragment、Service、Broadcast Receiver等等。 4. Vogella:提供了许多高质量的Android开发教程和文章,包括Android Framework的深入讲解。 5. Android Arsenal:提供了许多Android Framework相关的库和工具,可以帮助开发者更好地理解和应用Android Framework。 6. Square Engineering Blog:Square公司的技术博客,提供了许多有关Android Framework的文章和教程。 7. Big Nerd Ranch Blog:提供了许多有关Android Framework的文章和教程,同时也涵盖了其他技术领域。 8. AndroidPub:提供了许多有关Android Framework的文章和教程,同时也涵盖了其他技术领域。 以上是一些比较优秀的Android Framework博客,可以帮助你更好地掌握和应用Android Framework。 ### 回答2: Android Framework是一个庞大而复杂的系统,因此拥有许多优秀的博客可以帮助开发者理解和掌握该框架。下面是一些我认为优秀的Android Framework博客: 1. Android Developers Blog(https://android-developers.googleblog.com/):这是由Google官方维护的博客,提供关于Android开发的最新信息、最佳实践、新功能和更新。它是一个不可或缺的资源,对于与最新的Android开发相关的信息。 2. Android Weekly(http://androidweekly.net/):这是一个每周更新的电子邮件通讯,提供关于Android开发的最新新闻、文章和库。它是一个很好的资源,可以了解最新的趋势和技术。 3. Coding in Flow(https://codinginflow.com/):这个博客由一个经验丰富的Android开发者维护,他分享关于Android开发的教程、代码示例和技巧。他的博客和视频内容清晰易懂,非常适合初学者。 4. Mindorks(https://blog.mindorks.com/):这个博客提供有关Android开发经验和最佳实践的文章。它们的作者是经验丰富的开发者,可以提供一些高级的技术教程和案例研究。 5. Vogella(http://www.vogella.com/tutorials/android.html):这个网站提供了包括Android开发的广泛教程,从基础到高级的主题都有涉及。他们的教程结构清晰明了,非常适合初学者和有经验的开发者。 这只是一小部分与Android Framework相关的优秀博客。值得注意的是,为了跟上Android Framework的快速发展,开发人员应保持关注新的博客和资源,以继续提高他们的技能。 ### 回答3: Android框架在开发起着关键的作用,为了帮助开发者更好地了解和应用Android框架,有许多优秀的博客提供相关的内容和指导。以下是一些我认为优秀的Android框架博客: 1. Android Developers Blog:这是Android官方的博客,提供了关于新功能、最佳实践、开发技巧等方面的文章和更新。这个博客是了解Android框架的重要渠道之一。 2. Android开发技术周报:这是一个专注于Android开发的博客,每周发布技术文章、开源项目推荐以及一些实用的开发技巧。它涵盖了广泛的主题,包括Android框架的应用。 3. CSDN Android博客专栏:CSDN是国最大的技术社区之一,其Android博客专栏有很多优秀的博文和教程,覆盖了从入门到进阶的各个方面。其包括介绍Android框架的文章和案例分析。 4. 唐巧的技术博客:唐巧是一位知名的iOS和Android开发者,他的博客上有大量关于移动开发的文章,包括Android框架的解析和使用技巧。他的博客以深入易懂的解释和实践经验而受到广泛赞誉。 5. 思否专栏:思否是一个开发者社区,其专栏以高质量的技术文章而著名。在思否专栏,你可以找到许多关于Android开发和Android框架的博文,这些文章会帮助你深入理解和学习Android框架。 这些博客提供了不同层次和角度的Android框架相关内容,无论你是新手还是有经验的开发者,都可以在这些博客找到有用的信息和灵感。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值