基础说明:
oc一般可以采用声明protocol-delegate的形式进行回调,
声明协议P,A类遵循协议<P>,B类声明一个指针id<P> delegate;
然后通过A类的方法a调用B类的方法b,b方法中再self.delegate 调用协议方法,就实现了回调;
有一种情况就要注意OC对象的释放时机,一般情况下
- (void) test {
A * a = [[A alloc]init];
[a print];
}
print函数执行完,a就释放了。
如果print是个耗时操作,就会等一会儿。
下面改成:
//主函数中new个A
- (void) main {
A * a = [[A alloc]init];
[a test];
}
A异步执行B的start方法,start方法中会用self.delegate调用A的方法
- (void) test {
b = [[B alloc]init];
b.delegate = self;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[b start];
});
}
//B类中的start方法通过协议调用A的方法
- (void) start {
sleep(3);
[self.delegate methodA];
}
大家都知道要把delegate属性设成weak,在这种情况下,异步进入B的start方法,A的test已经执行完毕,就会被释放。b的delegate就成了空,methodA也不会执行了。
把delegate属性改成strong是一个办法,但诸多文章教你不要用strong的delegate。
另一种办法是给A加一个成员变量B * _b;也就是A持有B的实例,B没执行完A也不会释放,此时delegate必须要用weak。
回调的另一实现方法是使用block:
- (void) test {
b = [[B alloc]init];
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[b startBlock:^{
[weakSelf test];
}];
});
}
很多人无法区分何时使用
__weak typeof(self) weakSelf = self;
像上面代码的情况,没有互相持有的类,其实直接使用self即可,而且也不会出现提前释放的情况。
如果A包含了B的对象,就要用weakSelf,因为有时传进去的block会被B赋值给成员变量。如下:
typedef void(^Ablock)();
@implementation B {
Ablock ablock;
}
//如果在B类中,把传进去的block赋值给了B的一个成员变量
- (void) startBlock:(Ablock)completion {
ablock = completion;
if (completion) {
completion();
}
}
如果A调用时还是用self,就会出现循环引用,A无法释放,B也无法释放的情况。使用weakSelf总不会出错的,也不会出现提示释放的问题。
总而言之,循环引用就是,两个以上的变量,互相strong的持有,这个环的一节设成weak就打破了。
避免循环引用的同时还要注意A类提前释放,B的回调无法执行的情况。

支付宝打赏
微信打赏