在dispatch_async函数中使用弱自身

马克·扎德拉维克(Marko Zadravec)

我读了很多关于使用__weak selfinside的文章dispatch_async,现在我有点困惑。

如果我有 :

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];
    });
});

我需要使用吗__weak self因为我读到某些情况下dispatch_async不需要__weak self

在这里查看最新评论

CouchDeveloper

假设self是指向的对象指针UIViewController

注意事项:

  • AUIViewController是“ UIKit”对象。UIKit对象不得在非主线程上发送方法,即-这些方法只能在主线程上执行!

  • 无论是同步队列还是异步队列,已经排队的块最终都将被执行-无论如何!好吧,除非程序在此之前终止。

  • 捕获的可保留指针将在复制该块时保留(例如,异步调度时),并在该块被破坏时(完成后)再次释放

  • 捕获的可保留指针将不会保留或释放。

在您的情况,在那里你捕捉自己在其中的调度块主队列,您不必担心不好的事情发生。

所以为什么?实际发生了什么?

由于self将被捕获异步分发的块中,因此self将被隐式保留,并在块完成后再次释放

这意味着,自我的寿命延长,直到障碍完成为止。请注意,您的第二个块是在主线程上分派的,可以确保在执行该块时self仍然有效。

上面的“延长寿命”可能是程序的理想功能。

如果您明确不想延长UIViewController对象的寿命,而是希望该块(最终执行时)检查UIViewController对象是否仍然存在,则可以使用self的__weak指针。请注意,无论块UIViewController仍处于活动状态还是在此期间已被重新分配,该块都会最终执行

如果在块执行前已将其UIViewController释放您可能希望该块不执行任何操作

MyController* __weak weakSelf = self;
dispatch_async(queue, ^{
    MyController* strongSelf = weakSelf;
    if (strongSelf) {
        ...
    }
    else {
       // self has been deallocated in the meantime.
    }
});

另请参阅:过渡到ARC发行说明

切记:UIKit不得在非主线程上向对象发送方法!

由于UIKit对象只能在主线程上执行方法,因此可能会发生另一个细微的错误

如果块捕获UIKit异步分配对象并在非主线程上执行,则可能违反此规定然后,可能发生该块保留对该对象最后一个强引用的情况UIKit现在,当最终执行该块时,该块将被销毁并UIKit释放对象。由于这是对该对象的最后一个引用UIKit,因此将对其进行释放。但是,这发生在已执行该块的线程上-这不是主线程!现在,坏的事情可能(并且通常会发生)发生,因为该dealloc方法仍然是发送给UIKit对象的方法

您可以通过调度一个捕获指向该UIKit对象的强指针的块并将其发送给伪方法来避免此错误:

UIViewController* strongUIKitPointer = ... 
dispatch_async(non_main_queue, ^{
    ... // do something 
    dispatch(dispatch_get_main_queue(), ^{
        [strongUIKitPointer self];  // note: self is a method, too - doing nothing
    });
});

但是,在您的方案中,最后一个强引用只能在主线程上执行的块中。因此,您可以避免这种细微的错误。;)

编辑:

在您的设置中,您永远不会有保留周期。如果可保留对象A强烈引用另一个可保留对象B,而对象B强烈引用A,则发生保留周期。请注意,“块”也是可保留对象。

一个带有循环引用的人为示例:

typedef void(^my_completion_block_t)(NSArray* result);

@interface UsersViewController : UIViewController
@property (nonatomic, copy) my_completion_block_t completion;
@property (nonatomic) NSArray* users;
@end

在这里,我们有一个属性补全,其值类型为Block。也就是说,我们得到一个名称为_completion类型为Block的ivar

客户端可以设置一个完成处理程序,当某个操作完成时应调用该处理程序。假设该操作从远程服务器获取用户列表。该计划是在操作完成后设置属性用户

粗心的方法会偶然引入循环引用:

在“ UsersViewController.m”中的某个位置

self.completion = ^(NSArray* users){
    self.users = users;
}

[self fetchUsers];  // start asynchronous task

在这里,self对ivar拥有很强的参考力_completion,这是一个块。并且该块本身捕获self,这导致在分派块时复制该块时保留self这是一个经典的参考周期。

为了避免这种循环引用,我们有几种选择:

  1. 使用__weak合格的自我指针

    UsersViewController* __weak weakSelf = self;
    self.completion = ^(NSArray* users) {
        UsersViewController* strongSelf = weakSelf;
        if (strongSelf) {
            strongSelf.users = users;
        }
        else {
            // the view controller does not exist anymore
        }
    }   
    [usersViewController fetchUsers];
    
  2. 使用__block合格的self指针,nil在完成时最终将其设置在块中:

    UsersViewController* __block blockSelf = self;
    self.completion = ^(NSArray* users) {
        blockSelf.users = users;
        blockSelf = nil;
    }   
    [usersViewController fetchUsers];
    

另请参阅:过渡到ARC发行说明

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在Swift中使用Dispatch_Async更新UI

来自分类Dev

在Swift中使用dispatch_async并发分析数组

来自分类Dev

如何在Swift中使用dispatch_async?

来自分类Dev

来自函数的Swift dispatch_async

来自分类Dev

使用dispatch_sync和dispatch_async同步对嵌套异步函数的调用

来自分类Dev

使用dispatch_async并行搜索

来自分类Dev

在 dispatch_async 队列中的弱自我(dispatch_get_main_queue(),^{})

来自分类Dev

无法在Swift iOS中使用dispatch_async方法更新UILabel

来自分类Dev

iOS-使用CoreData的dispatch_async保留周期

来自分类Dev

未使用dispatch_async调用并重复NSTimer的方法

来自分类Dev

与self一起使用dispatch_async

来自分类Dev

使用cellForRowAtIndexPath中的dispatch_async加载图像

来自分类Dev

使用dispatch_async在后台加载图像

来自分类Dev

Using dispatch_async with self

来自分类Dev

如何使dispatch_async运行

来自分类Dev

使用Objective-C中的主要中央dispatch / dispatch_async返回后台队列

来自分类Dev

使用dispatch_async + dispatch_get_main_queue进行UI更新有什么意义?

来自分类Dev

使用Objective-C中的大型中央dispatch / dispatch_async返回后台队列

来自分类Dev

dispatch_async尚未完成

来自分类Dev

在dispatch_async中调用委托方法

来自分类Dev

未调用dispatch_async块

来自分类Dev

Swift:从dispatch_async内部返回结果

来自分类Dev

无需回调的OCMock for dispatch_async

来自分类Dev

在dispatch_async中调用委托方法

来自分类Dev

使用dispatch_async,使用您自己的单个队列还是自己的全局队列?

来自分类Dev

提取数据中的dispatch_async与dispatch_sync。迅速

来自分类Dev

NSManagedObjectContext内的dispatch_async(dispatch_get_main_queue()

来自分类Dev

提取数据中的dispatch_async与dispatch_sync。迅速

来自分类Dev

iOS:dispatch_async(dispatch_get_main_queue())

Related 相关文章

  1. 1

    在Swift中使用Dispatch_Async更新UI

  2. 2

    在Swift中使用dispatch_async并发分析数组

  3. 3

    如何在Swift中使用dispatch_async?

  4. 4

    来自函数的Swift dispatch_async

  5. 5

    使用dispatch_sync和dispatch_async同步对嵌套异步函数的调用

  6. 6

    使用dispatch_async并行搜索

  7. 7

    在 dispatch_async 队列中的弱自我(dispatch_get_main_queue(),^{})

  8. 8

    无法在Swift iOS中使用dispatch_async方法更新UILabel

  9. 9

    iOS-使用CoreData的dispatch_async保留周期

  10. 10

    未使用dispatch_async调用并重复NSTimer的方法

  11. 11

    与self一起使用dispatch_async

  12. 12

    使用cellForRowAtIndexPath中的dispatch_async加载图像

  13. 13

    使用dispatch_async在后台加载图像

  14. 14

    Using dispatch_async with self

  15. 15

    如何使dispatch_async运行

  16. 16

    使用Objective-C中的主要中央dispatch / dispatch_async返回后台队列

  17. 17

    使用dispatch_async + dispatch_get_main_queue进行UI更新有什么意义?

  18. 18

    使用Objective-C中的大型中央dispatch / dispatch_async返回后台队列

  19. 19

    dispatch_async尚未完成

  20. 20

    在dispatch_async中调用委托方法

  21. 21

    未调用dispatch_async块

  22. 22

    Swift:从dispatch_async内部返回结果

  23. 23

    无需回调的OCMock for dispatch_async

  24. 24

    在dispatch_async中调用委托方法

  25. 25

    使用dispatch_async,使用您自己的单个队列还是自己的全局队列?

  26. 26

    提取数据中的dispatch_async与dispatch_sync。迅速

  27. 27

    NSManagedObjectContext内的dispatch_async(dispatch_get_main_queue()

  28. 28

    提取数据中的dispatch_async与dispatch_sync。迅速

  29. 29

    iOS:dispatch_async(dispatch_get_main_queue())

热门标签

归档