如果一个强大的属性有一个引用self的块,那是一个保留周期吗?

时间:2013-03-26 20:47:16

标签: ios objective-c objective-c-blocks

例如:

[self.contentWrapperView addGestureRecognizer:
   [UITapGestureRecognizer recognizerWithHandler:^(UIGestureRecognizer *sender, 
                                                   UIGestureRecognizerState state, 
                                                   CGPoint location) {
        if (self.customEditing) {
        [self setEditingMode:NO Animated:YES];
      }
    }]];

其中contentWrapperViewself上的强属性,并假设contentWrapperView具有对识别器块的强引用。在块中使用self是否会导致保留周期?这是我不太了解的唯一部分。

2 个答案:

答案 0 :(得分:4)

是的,它会导致保留周期。

你需要关心的解决方法是

__weak id weakSelf = self;
[self.contentWrapperView addGestureRecognizer:[UITapGestureRecognizer recognizerWithHandler:^(UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location) {
    if ([weakSelf customEditing]) {
        [weakSelf setEditingMode:NO Animated:YES];
    }
}]];

答案 1 :(得分:4)

根据实际情况考虑保留周期:通过您拥有的对象保留自己。

在Cocoa和Cocoa-Touch的术语中,这意味着您拥有强烈的任何变量都不能强烈地拥有。这通常是通过声明需要拥有其父weakunsafe_unretainedassign的属性来解决的。这会使块变得复杂,这些块通常用作闭包,捕获const或保留对其中每个变量的引用(显然,__block限定符会进一步复杂化。)

不是从块的角度来看这个,我会尝试将它抽象成一个带有两个类的例子,对于那些在OO lang中的人来说通常更容易接受:

假设我有课程MyImportantObject,需要与另一个课程MyWorkerClass合作。我们通常希望强烈引用MyWorkerClass,因为我们可能希望它继续存在,以便我们可以稍后再做一些工作,或者继续一遍又一遍地调用相同的工作方法:

@interface MyImportantObject : NSObject 

@property (nonatomic, strong) MyWorkerClass *workerObj;

@end

反过来,我们的工作人员需要稳定引用它需要工作的所有MyImportantObject属性(否则它不能工作!)。那么阻止引用self的是什么,而不是对每个变量进行const或保留引用,它们会保留对其父级的引用!

@interface MyWorkerClass : NSObject 

@property (nonatomic, strong) MyImportantObject *workerObj;

@end

这意味着如果您尝试使用MyImportantObject的工作对象,他们会相互保留,并且都不会被正确释放!巨大的禁忌。

通过将self分流到__weak(或MRC下的__block)指针,我们会得到一个如下所示的引用:

@interface MyWorkerClass : NSObject 

@property (nonatomic, weak) MyImportantObject *workerObj;

@end

没有更多的保留周期,每个人都很开心,当父母走上恐龙之路时,每个人都会得到适当的解除分配。

但还有一个难题:我们如何处理weak参考?毕竟,让我们说好的'编译器出现了,并且快速self从你身下抽出-release。由于这个归零弱指针,你现在有一个nil指针在你的块中运行。这可能导致它实际上什么都不做,而你坐在那里,挠头想知道为什么。这导致了我所说的弱势舞蹈的发明。

J_mcnally的例子是缺少舞蹈中的一个关键步骤,即你的自我指针的“重新强化”。但是,为什么我们只是在为了避免保留周期而遇到所有麻烦之后想要这样做呢?这是因为我们强大的X副本没有被块保留,它被块的范围保留。在英语中,这意味着我们的强self只会在块结束时解除分配,从而不仅保证了一个安全的内存周期,而且它不会从我们下面解除分配。正确的解决方案如下所示:

__weak id weakSelf = self;
[self.contentWrapperView addGestureRecognizer:[UITapGestureRecognizer recognizerWithHandler:^(UIGestureRecognizer *sender, UIGestureRecognizerState state, CGPoint location) {
    id strongSelf = weakSelf;
    if ([strongSelf customEditing]) {
        [strongSelf setEditingMode:NO Animated:YES];
    }
    //Do some other stuff before strongSelf passes out of scope.
}]];