Block
实际上就是 Objective-C 语言对于闭包的实现。对于 Block
的基本认识和使用,这里推荐一个博客 iOS开发-由浅至深学习block ,这里不在多做过多的描述.本文主要讲关于Block
的weak-strong dance
.
weak-strong dance
使用 Block 时可以通过__weak来避免循环引用已经是众所周知的事情:
// OCClass.m
__weak typeof(self) weakSelf = self;
self.handler = ^{ NSLog(@"Self is %@", weakSelf); };
这时handler
持有 Block 对象,而 Block 对象虽然捕获了weakSelf
,延长了weakSelf
这个局部变量的生命周期,但weakSelf
是附有__weak
修饰符的变量,它并不会持有对象,一旦它指向的对象被废弃了,它将自动被赋值为nil
。在多线程情况下,可能weakSelf指向的对象会在 Block 执行前被废弃,这在上例中无伤大雅,只会输出Self is nil,但在有些情况下(譬如在 Block 中有移除KVO
的观察者的逻辑,在执行到该逻辑前 self
就释放了)就会导致 crash。这时可以在 Block 内部(第一句)再持有一次weakSelf
指向的对象,保证在执行 Block 期间该对象不会被废弃,这就是所谓的 weak-strong dance
:
__weak typeof(self) weakSelf = self;
self.handler = ^{
typeof(weakSelf) strongSelf = weakSelf;
// ...
[strongSelf.obserable removeObserver:strongSelf
forKeyPath:kObservableProperty];
};
typeof(weakSelf) strongSelf = weakSelf
这一句等于__strong typeof(weakSelf) strongSelf = weakSelf
,在 ARC 模式下,id 类型和 OC 对象类型默认的所有权修饰符就是__strong
,所以是可以省略的。
顺便说一下,__weak
修饰的变量不会持有对象,它用一张 weak 表(类似于引用计数表的散列表)来管理对象和变量。赋值的时候它会以赋值对象的地址作为 key
,变量的地址为value
,注册到 weak 表中。一旦该对象被废弃,就通过对象地址在 weak 表中找到变量的地址,赋值为 nil
,然后将该条记录从 weak 表中删除。