iOS 什么情况下weak self需要配合strong self使用
2017-09-20 14:53
435 查看
前言
对于block和weak self这一对欢喜冤家,这篇博文默认你对此已经很熟悉了。如果还不清楚block的几种形式,以及在什么情况下必须使用weak point什么情况下可以使用strong point,可以参考《block之三种blcok》 以及《block之循环引用》。
综述
一般情况下我们使用__weak关键字定义一个强指针的弱引用;用__strong关键字定义一个弱指针的强引用,如下://__weak定义了一个指向self的弱指针weakS,当self释放之后weakS被置为nil __weak typeof(self) weakS = self; //这里的strongS是个强指针,如果strongS初始化时self未释放,则在strongS被引用过程中self都会被保留而不会释放 __strong typeof(weakS) strongS = weakS;
使用weak关键字定义的指针不强引用对象,当变量释放后会自动置为nil,这一点和assign有所区别。
使用strong关键字定义的指针会强引用对象,当自身释放后,强引用对象才会释放。
weak 情景1 - 使用weak很安全
在使用block的过程中,我们经常见到的情况是这样://代码片段1 __weak typeof(self) weak = self; void (^block1)() = ^{ //为避免循环引用,在作为property的block中使用self的弱指针 NSLog(@" -- %@ --",weak); }; _v.block1 = block1;
当然这样不会有什么问题,打印结果无非就两种,分别对应self释放与未释放,如下:
//self未释放 2017-09-20 13:52:21.025 BlockDemo[4237:149469] -- <BVC: 0x7fab00905040> -- //self已经释放 2017-09-20 13:52:24.438 BlockDemo[4237:149469] -- (null) --
weak 情景2 - weak并不总是安全
但是,你也可能遇到如下情况://代码片段2 __weak typeof(self) weakS = self; void (^block1)() = ^{ NSLog(@" -- %@ --",weakS); //这里模拟一个dispatch_async,因为dispatch_after其实就是异步的 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@" == %@ ==",weakS); }); }; _v.block1 = block1;
猜测一下会有几种打印结果呢?
答案是3种,带着疑惑请继续往下看:
1、两次打印self都没有释放 2017-09-20 13:47:33.090 BlockDemo[4141:145270] -- <BVC: 0x7fde2d806940> -- 2017-09-20 13:47:35.270 BlockDemo[4141:145270] == <BVC: 0x7fde2d806940> == 2、两次打印self都释放了 2017-09-20 13:49:09.955 BlockDemo[4141:145270] -- (null) -- 2017-09-20 13:49:12.154 BlockDemo[4141:145270] == (null) == 3、第一次打印self未释放,第二次打印self释放了 2017-09-20 13:50:02.526 BlockDemo[4190:147582] -- <BVC: 0x7fcc98d02690> -- 2017-09-20 13:50:04.526 BlockDemo[4190:147582] == (null) ==
我们都知道,一般情况下(形如代码片段1)在block中使用weak self,如果block入栈时self未释放,则在block出栈前self是不可能被释放的,因此第一段代码只有两种可能性。
代码片段2就是另一种情形了,我来解释一下为什么会出现两次打印结果不一样的情况:
在block1入栈时self未释放,因此第一个NSLog()能打印出self的内存地址;
第二个NSLog()之所以打印出了(null),问题就在于block1出栈后,dispatch_after的代码块还未入栈,而self恰恰就在block1出栈后,而dispatch_after入栈前释放了,因此第二个NSLog()打印出了(null)。
dispatch_after明明就是写在block1中的,为什么block1出栈时,它还没入栈呢?
要想理解这个问题,首先要知道dispatch_after实际上是异步的,即它的实现实际上是基于dispatch_async的,执行时会立即返回,并不会卡主线程。
dispatch_async的作用就是将它的block任务块放进相应的队列中(队列其实就是任务列表),等待相关线程去执行,至于什么时候执行(函数入栈后才能执行)存在不确定性。
至此,你是否已经明白了为什么代码片段2中可能出现前后两次打印结果不一致的情况?
后续
如果已经对代码片段2出现的第三种打印情况有所了解,应该也就知道了本篇博文所讨论的问题答案了。面对代码片段2的情况,我们只需要在block1中创建weakS的强引用即可保证block1和dispatch_after中的self相同(都未释放/都是nil)
__weak typeof(self) weakS = self; void (^block1)() = ^{ NSLog(@" -- %@ --",weakS); __strong typeof(weakS) strongS = weakS; //BVC * vc = weakS; 这种形式和__strong typeof(weakS)相同 //strongS其实只是个局部变量的强指针,它在作用域内不会被释放 //这里模拟一个dispatch_async,dispatch_after其实就是异步的 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@" == %@ ==",strongS); }); }; _v.block1 = block1;
总结
总结一下strong self配合weak self使用的条件block中用到了weak self
block中包含异步操作
异步操作中用到了self
当以上三个条件都成立的时候,为了避免block和异步操作中self(所有强指针)不一致,则应该在block中定义weak point的强引用,并在异步操作中使用。
//以下两种方式定义都是可以的,只是习惯上使用__strong __strong typeof(weakS) strongS = weakS; BVC * strongS = weakS;
如有不妥之处,欢迎指正,谢谢!
相关文章推荐
- ios 什么情况下使用assign,copy,retain,strong,weak
- iOS 闭包中的[weak self]在什么情况下需要使用,什么情况下可以不加?
- 【IOS学习】到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf
- iOS 面试题(3.):为什么 weakSelf 需要配合 strong self 使用
- iOS 面试题(三):为什么 weakSelf 需要配合 strong self 使用 --转自唐巧
- 到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf
- SPRING事务的属性有哪些?其中,事务隔离级别有哪几种?什么情况需要使用这几种事务隔离级别?
- 到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf
- 什么情况使用 weak 关键字,和assign何不同?
- 个人理解:什么情况下需要使用protected修饰类成员变量
- Ibatis 在什么情况需要使用remapResults属性
- 到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf
- 到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf
- 什么情况下需要使用的稳压器?
- Python入门:自定义类中的方法被调用的时候,什么情况下需要传入self,什么时候不需要
- 到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf
- 到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf
- 什么情况下需要使用VPS
- 什么情况下我们使用copy,assign,retain,strong,weak?
- 到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf