美文网首页iOS 笔记
Block 中何時可以直接用 self,何時必須用 weakSe

Block 中何時可以直接用 self,何時必須用 weakSe

作者: Dayon | 来源:发表于2018-05-24 16:43 被阅读0次

若 object 本身没有去 retain 这个 block (即没有把这个 block 作成一个 property),则可以直接在 block 中使用 self

//block 不是 property
dispatch_block_t completionBlock = ^{
    // 未 retain block,可直接用 self
    NSLog(@"%@", self);
}
MyViewController *myController = [[MyViewController alloc] init...];
[self presentViewController:myController
                   animated:YES
                 completion:completionHandler];
//把这个 block 作成一个 property
self.completionHandler = ^{
    // 有 retain block,直接用 self 会造成 retain cycle
    NSLog(@"%@", self);
}
MyViewController *myController = [[MyViewController alloc] init...];
[self presentViewController:myController
                   animated:YES
                 completion:self.completionHandler];

当有 retain block 时,应该使用 weakSelf

__weak typeof(self) weakSelf = self;
self.completionHandler = ^{
    // 打破 retain cycle
    NSLog(@"%@", weakSelf);
};

MyViewController *myController = [[MyViewController alloc] init...];
[self presentViewController:myController
                   animated:YES
                 completion:self.completionHandler];

但只用 weakSelf 的问题在于,如果在 block 中必须多次使用到 weakSelf 会有危险,因为在多事件执行时,weakSelf 有可能在 block 跑到一半的时候被设成 nil

__weak typeof(self) weakSelf = self;
dispatch_block_t block =  ^{
    [weakSelf doSomething]; // weakSelf != nil
    // preemption, weakSelf turned nil
    [weakSelf doSomethingElse]; // weakSelf == nil
};

因此必须在 block 内使用 strongSelf,确保 reference 不会执行到一半变成 nil (注意在建立 strongSelf 以后还会再判断其是否为 nil,因为有可能在指定 strongSelf 的时间点 weakSelf = self 就已经为 nil 了)

__weak typeof(self) weakSelf = self;
myObj.myBlock =  ^{
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf doSomething]; // strongSelf != nil
      // preemption, strongSelf still not nil
      [strongSelf doSomethingElse]; // strongSelf != nil
    }
    else {
        // Probably nothing...
        return;
    }
};

总结:

  1. 当 block 不是 property 时,用 self 即可
  2. 当 block 是 property,需使用 weakSelf
  3. 当 block 内会多次使用 weakSelf,且有用到多次执行时,需使用 strongSelf
  4. 并不是所有 block 都得用 weakSelf

事实上大多数的 iOS 原生套件,以及 GCD 的 block 是不会造成 retain cycle 的,因为他们并没有去 retain block

此外也可以因为把 block property 设为 nil 来打破 retain cycle
例如 AFNetworking 就使用了类似的操作方式
因此在 AFNetworking 的 block 中使用 self 也不会造成 retain cycle 问题

另外即使将变量声明成 instance variable(实例变量) 而非 property(属性),在 block 中使用时还是会 retain 到 self 而发生 retain cycle,因为 ivar 其实也是 self 的一部份

@interface MyViewController () {
    NSString *tempStr;
}

self.completionHandler = ^{
    // 这里的 tempStr 相当于 self->tempStr,因此还是会造成 retain cycle
    NSLog(@"%@", tempStr);
}

但 ivar 又无法使用 weakSelf 去取值,因此解決方法有:

  • 1、乖乖建立 property (可能比较简单)
  • 2、使用 weakSelf + strongSelf
 __weak __typeof(self) weakSelf = self;
self.completionHandler = ^{
    // 用 weakSelf->tempStr 是无法取值的
    __strong __typeof(weakSelf) strongSelf = weakSelf;
    NSLog(@"%@", strongSelf->tempStr);
}

更详细说明参照:
https://github.com/oa414/objc-zen-book-cn#-block
http://blog.waterworld.com.hk/post/block-weakself-strongself

相关文章

  • Block 中何時可以直接用 self,何時必須用 weakSe

    若 object 本身没有去 retain 这个 block (即没有把这个 block 作成一个 proper...

  • iOS人機交互指南(04)——應用開啓和關閉

    立刻開啓 一般來說,用戶只會花一、兩分鐘的時間試用一個新應用,必須在很短的時間內把應用的有用信息呈現出來。 不要讓...

  • 風 放縱,何時與我相遇 流年,何時與我相見 花火,何時吹響遠笛 風,何時喚醒廢木 風,何時放縱,流年里,吹滅花火 ...

  • 八個問自己的問題?

    早晚有一天,我要做到『時間自由』。為了長期目標,我必須重新思考以下問題: 1、我必須要關注什麼? 答:時時刻刻關注...

  • 不知何時

    不知何時ㄧ徐子泓 不知何時 天上雲散了 空中高掛彩虹 小燕往南飛去 是寥寥數天 還是一年半載? 恍然一刹那 樹林換...

  • 夜興感懷二首

    其一 石橋竹影臥清風,騷人獨憶舊夢中。 久病須臾人事改,何時把酒月下逢? ...

  • 2018-10-12 iOS中block造成的循环引用

    主要还是看self->block->self,会不会产生这样的环。 引自:关于Block内部要不要使用weakSe...

  • 【心畫】閑情偶寄·頤養部·飯粥(三)·清·李漁

    半暇·得半日清閑,抵十年塵夢 | 臨硯 | 原文 宴客者有時用飯,必較家常所食者稍精。精用何法?曰:使之有香而已矣...

  • 2020-07-03

    何時返天下

  • 何時長向

    我在家乡呆了21年,幼儿园、小学、初中、大学都在同一个地方。大学的寝室回家,走路只消二十分钟。 我是家里的独女,父...

网友评论

    本文标题:Block 中何時可以直接用 self,何時必須用 weakSe

    本文链接:https://www.haomeiwen.com/subject/memsjftx.html