如果一个强属性有一个指向self的块,那是一个retain循环吗?



例如:

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

其中contentWrapperViewself上的强性质,假设contentWrapperView对识别块有强引用。在块中使用self会导致保留循环吗?这是我唯一不太明白的部分。

是的,这将导致一个保留循环。

如果你关心的是

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

从保留周期的实际意义来考虑它:你所拥有的一个对象对你自己的保留。

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

我不从代码块的角度来看待这个问题,而是尝试将其抽象为一个包含两个类的示例,这对于使用OO语言的人来说通常更容易理解:

假设我有一个类MyImportantObject,它需要与另一个类MyWorkerClass做一些工作。我们通常需要MyWorkerClass的强引用,因为我们可能希望它保留下来,以便以后可以做更多的工作,或者继续一遍又一遍地调用相同的工作方法:

@interface MyImportantObject : NSObject 
@property (nonatomic, strong) MyWorkerClass *workerObj;
@end
反过来,我们的worker需要一个稳定的对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引用?毕竟,让我们假设好的编译器出现了,用一个快速的-releaseself从你下面拉出来。因为那个归零弱指针,你现在有一个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.
}]];

相关内容

最新更新