一、 Block
- 认识 Block
- Block 的循环引用
二、委托与数据源
- 委托与数据源
三、通知
一、Block
认识 Block
一些关键点:
- Block 是在栈上创建的
- Block 可以复制到堆上
- 如果在 Block 中修改Block 外的变量, 那么这些变量就应该用 __block 来声明
如果 Block 没有在其他地方被引用, 那么他的生命周期与栈同步,即生命周期由系统控制, 所以仅存在栈上时, Block 对对象的内存管理和生命周期并没有影响, 例如我们在使用 UIView 动画 Block 的时候.
如果 Block 需要在栈返回的时候存在, 那么他们需要被复制到堆上, 并且会 retain 他所有引用的对象.
如果 Block 引用了一个栈变量, 那么 Block 在初始化的时候就会拥有这个变量的 const 副本, 所以不能给这个 const 副本赋值, 否则报错.
self 的循环引用:
比如单语句情况:
__weak __typeof(self) weakSelf = self;
[self executeBlock:^(NSData *data, NSError *error) {
[weakSelf doSomethingWithData:data];
}];
不要这样:
[self executeBlock:^(NSData *data, NSError *error) {
[self doSomethingWithData:data];
}];
多语句的情况:
__weak __typeof(self)weakSelf = self;
[self executeBlock:^(NSData *data, NSError *error) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf doSomethingWithData:data];
[strongSelf doSomethingWithData:data];
}}];
不要这样:
__weak __typeof(self)weakSelf = self;
[self executeBlock:^(NSData *data, NSError *error) {
[weakSelf doSomethingWithData:data];
[weakSelf doSomethingWithData:data];
}];
顺便把这两行加入到你的 Snippet 中方便使用:
__weak __typeof(self)weakSelf = self;
__strong __typeof(weakSelf)strongSelf = weakSelf;
接下来我们来讨论一下 Block 里面使用 ______weak 与 ________strong 的作用, 分别有以下三种方案:
- 直接在 block 里面使用 self
- 在 block 外面定义一个________ weak引用到 self, 在 block 里面使用这个 self
- 在 block 外面定义一个________ weak引用到 self, 再在 block 内部定义一个________ strong 引用到 self, 再使用这个 self
方案1:
如果是在栈 Block 那么关系并不大,但是在堆 Block就会出现有名的 retain cycle 问题,这种情况下我们收到 CLANG 的警告:
Capturing 'self' strongly in this block is likely to lead to a retain cycle
所以 __weak就有用武之地了,见方案2。
方案2:
不管 Block 是否作为属性被 retain,使用__weak就不会发生循环引用的问题。
但是有没有考虑到出现这种问题:在调用这个 Block 的时候,weakSelf 已经被销毁导致坏内存出现,所以方案3诞生了。
方案3:
方案3使用__weak已经解决了循环引用的问题。
那么这么写还有一个好处在于:当 Block 被执行的时候,weakSelf 才被 strongSelf 强引用着,如果这个时候 weakSelf 已经被销毁,那么strongSelf也是空就不会执行下面方法,如果weakSelf 未销毁,那么被strongSelf retain 后也不会再被销毁,执行下面的方法就是安全的了。
网友评论