ios开发

Objective-C Block Part3 - Weak-S

2017-03-30  本文已影响50人  f939f3106e72

什么是 Weak-Strong Dance ?

在使用的 Block 时, 除了使用 __weak 修饰符去避免循环引用外,还可以通过名为 Weak-Strong Dance 的方式去避免循环引用。 其实 Weak-Strong Dance 并不是一个新东西,它只是 __weak 的一个升级版本。主要目的是为了避免在极端情况下 __weak 这种情况会出现的问题。

使用 __weak 形式避免循环引用有什么问题?

typedef void(^blk_t)();

@interface TObject : NSObject
@property (nonatomic) blk_t block;
@end
@implementation TObject
- (instancetype)init {
    self = [super init];
  
    __weak typeof(self) weakSelf = self;
    self.block = ^() {
      NSLog(@"block start...");
      NSLog(@"self is %@", weakSelf);
      NSLog(@"block   end...");
    };  
    return self;
}
@end

上面这段代码在大部分的情况下都是可行的,Block 捕获 weakSelf。当 self 被释放的时候, weakSelf 也会被设为 nil。self 持有的 Block 当然也会被设为 nil 。但是在多线程的情况当 block 执行到 NSLog(@"block start...") 时, 在另一个线程中此时 self 被释放。 weakSelf 也被设为 nil 。那么这个例子中就会打印出 self is nil 。这没出现啥问题。 但是如果是移除 KVO 的观察者,或者添加到 NSDictionary 中这样的 API。值为 nil 就会造成程序 carsh。

通过 Weak-Strong Dance 安全的避免循环引用

- (instancetype)init {
    self = [super init];
    
    __weak typeof(self) weakSelf = self;
    self.block = ^() {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSLog(@"%@", strongSelf);
    };   
    return self;
}

通过对上面的代码增加了一句 __strong typeof(weakSelf) strongSelf = weakSelf; 来避免了上面说的极端情况,这就是 Weak-Strong Dance 。 这句话的作用在于一执行 Block 的时候,就利用一个强引用去持有 weakSelf。 这样在 Block 执行的过程中就不用担心 self 会被释放了, 因为此时有个强引用持有他。这也不会造成循环引用,因为 Block 执行时 strongSelf 才会指向 self,Block 执行完成后 strongSelf 就随着超出作用域而被系统回收了。

拓展&加深

@kuailejim 的文章 Weak-Strong-Dance真的安全吗?》 看到个新的观点: 当刚进入 Block 时还没有为 strongSelf 赋值时,此时 weakSelf 被设置成 nil ,那 strongSelf 的值还是 nil 。 还是不够安全,所以在对 strongSelf 赋值后,再做一次非空判断。这样就绝对没毛病了:

__weak typeof(self) weakSelf = self;
self.block = ^() {
    __strong typeof(weakSelf) strongSelf = weakSelf;
    if (strongSelf == nil) {return;};
    NSLog(@"%@", strongSelf);
};
上一篇 下一篇

猜你喜欢

热点阅读