用嵌套块保留自己?

时间:2014-02-05 13:57:16

标签: ios objective-c scope automatic-ref-counting objective-c-blocks

使用以下代码:

@interface MyClass()
{
   NSMutableArray * dataArray;
}
@end

@implementation MyClass

- (void) doSomething
{
    __typeof__(self) __weak wself = self;
    dispatch_async(dispatch_get_global_queue(0,0), ^{
       __typeof__(self) sself = wself;
       [sself->dataArray addObject: @"Hello World"];

       dispatch_async(dispatch_get_main_queue(), ^{
         [NSThread sleepForTimeInterval: 30];

         UIAlertView *alert = [[UIAlertView alloc] initWithTitle: sself->dataArray[0] 
                                                         message: @"Message"
                                                        delegate: nil
                                               cancelButtonTitle: @"OK"
                                               otherButtonTitles: nil];
         [alert show];
       });
    });
}

@end
  1. 这是从主队列块中访问sself的正确方法吗?
  2. 初始队列结束后,sself是否会超出范围?
  3. 我应该在主队列块中添加第二个__typeof__(self) sself = wself;吗?

2 个答案:

答案 0 :(得分:2)

  1. 是的,确定是。
  2. 不,你可以在main_queue块中使用。
  3. 不,你不必。即使在global_queue块中也不必添加__typeof__(self) sself = wself;;没有必要,你已经有一个弱化的自我对象wself(此外,你会在块内的self部分保留__typeof__(self)
  4. 您不必使用__typeof__。仅使用typeof(self)

答案 1 :(得分:1)

你问:

  

这是从主队列块中访问sself的正确方法吗?

几乎。您还应该检查以确保sself不是nil。这样做是因为取消引用nil指针的ivar可能会导致应用程序崩溃。因此,请检查以确保它不是nil

- (void) doSomething
{
    typeof(self) __weak wself = self;
    dispatch_async(dispatch_get_global_queue(0,0), ^{
       typeof(self) sself = wself;
       if (sself) {
           [sself->dataArray addObject: @"Hello World"];

           dispatch_async(dispatch_get_main_queue(), ^{
             [NSThread sleepForTimeInterval: 30];

             UIAlertView *alert = [[UIAlertView alloc] initWithTitle: sself->dataArray[0] 
                                                             message: @"Message"
                                                            delegate: nil
                                                   cancelButtonTitle: @"OK"
                                                   otherButtonTitles: nil];
             [alert show];
           });
        }
    });
}

然后你问:

  

初始队列结束后,sself会超出范围吗?

它超出范围,但由内部块保留,并将保留直到该内部块完成。

  

我应该在主队列块中添加第二个__typeof__(self) sself = wself;吗?

如果你愿意,你可以,但没有必要。这取决于所需的行为。例如,如果您想要查看此警报,即使当前对象(可能是视图控制器)被解除,也请使用sself模式(因为您可能希望依赖它,以便您可以访问{{ 1}})。如果您不想再显示提醒,则请重复此dataArray / weakSelf舞蹈。