zoukankan      html  css  js  c++  java
  • dispatch_async 的 block 中是否该使用_weak self

    问题分析

    我看过很多文章关于在dispatch_async的block里面使用_weak self, 但是让我疑惑的是,以下代码是否需要必须使用_weak self, 因为我也看到了很多观点说,在有些情况下不需要使用__weak self.

    self.myQueue = dispatch_queue_create("com.biview.core_data", NULL);
    
    dispatch_async(self.myQueue, ^(void){
        if(!self.var1){
            self.var1 = 
        }
    
        dispatch_async(dispatch_get_main_queue(), ^(void){
            if([self.var2 superview]) {
                [self.var2 removeFromSuperview];
            }
    
            [self.Label setText:text];
        });
    });复制代码

    解析

    针对上面的问题,我们假设:self是指向UIViewController的对象指针。
    考虑以下几点:

    • UIViewController是"UIkit"对象,UIKit对象不应该在非主线程发送消息,也就是说,这些方法只能在主线程中执行。
    • 当一个block被添加进一个同步或者异步队列,这个block最终都会被执行,除非在执行到它之前应用程序被杀死。
    • 当block被拷贝的时候,strong类型的指针会被retained, 当block执行完毕之后被销毁的时候才会执行released操作。
    • weak类型的指针不会被retained和released。

    在上面的例子中,self是在主线程的队列中,不必担心有任何bug产生。

    究竟发生了什么?

    当在dispatch的异步队列的block中捕获到self时,self会被执行retained操作,当block执行完毕后self执行released操作。
    这意味着:当block执行完毕后,self的生命周期才会结束。上例中的第二个block是在主线程的队列中,它保证了self一直存活着当这个block被执行的时候。
    在程序中存在潜在危险的操作是:延长 self 的生命周期。

    如果你明确的不希望延长UIViewController对象的生命周期,而是当block被执行的时候去检查UIViewController对象到底是否存在,你可以使用 _weak self. 需要注意的是block最后都会被执行,不管UIViewController是否存活还是已经被释放了。

    如果你希望如果UIViewController已经被释放了,那么block不做任何事情,可以写成 _weak self.

    MyController * _weak weakSelf = self;
    dispatch_async(queue, ^{
        MyController *strongSelf = weakSelf;
        if(strongSelf){
            ...
        }else {
            // self has been deallocted in the meantime.
        }
    });复制代码

    不能在非主线程中向UIKit对象发送消息。
    另一个细微的错误可能发生在UIKit对象执行方法在非主线程。

    如果block在异步线程中捕获了一个UIKit对象,可能发生的是:block 是最后一个持有改UIKit的强引用。当block执行完的时候,UIKit对象将被release,因为是UIKit对象的最后一个强引用,所有该UIKit对象将被释放,但是,释放操作发生在block所执行的线程-它不是主线程,所有,风险即将发生,UIKit对象的dealloc方法将被调用(UI 对象应该在主线程中被回收,因为在它们的 dealloc 方法被调用回收的时候,可能会去改变 view 的结构关系,而如我们所知,这种操作应该放在主线程来进行,见参考二)。

    避免这个错误:

    UIViewController *strongUIKitPointer = ...
    dispatch_async(non_main_queue), ^{
        ...//do someting
        dispatch(dispatch_get_main_queue(),^{
            [strongUIkitPointer self]; //self is a method, too -doing nothing.
        });
    });复制代码

    举例

    双向强引用发生在:一个强类型对象A持有一个强类型对象B,并且对象B强引用对象A。“Block”是一个强引用对象。

    人为的双向强引用举例:

    typedef void(^my_completion_block_t)(NSArray* result);
    
    @interface UserViewController : UIViewController
    @property (nonatomic, copy) my_completion_block_t completion;
    @property (nonatomic) NSArray *users;复制代码

    on "UserViewController.m"

    self.completion = ^(NSArray *users){
        self.users = users;
    }
    [self fetchUsers];复制代码

    这是一个典型了强引用循环。UserViewController 有一个Block类型的属性,所有UserViewController对象强引用着block。而block捕获到self的时候执行强引用操作,所有形成了强引用循环。

    解决方式:

    1. 使用_weak 指针指向self.

      UserViewController * _weak weakSelf = self;
      self.completion = ^(NSArray *user){
       UsersViewController *strongSelf = weakSelf;
       if(strongSelf){
           strongSelf.users = users;
       }else{
           // the view controller does not exist anymore.
       }
      };复制代码
    2. 使用block 指针执行self, 执行完毕后将block 指针指向nil.

      UsersViewController *__block blockSelf = self;
      self.completion=^(NSArayy *users){
       self.completion = ^(NSArray *users){
           blockSelf.users = users;
           blockSelf = nil;
       }
      }复制代码

    --完--

    参考

    1. stack overflow
    2. objc-cn
  • 相关阅读:
    利用Python中SocketServer 实现客户端与服务器间非阻塞通信
    Redis单机配置多实例,实现主从同步
    Django(一) 安装使用基础
    数组模拟环形队列
    单链表原理及应用举例
    中缀表达式转换为后缀表达式(思路)
    中缀表达式转后缀表达式(代码实现)及前缀表达式思路补充
    数组模拟栈(Stack)
    双向链表原理及应用举例
    单向环形链表
  • 原文地址:https://www.cnblogs.com/twodog/p/12141276.html
Copyright © 2011-2022 走看看