在使用block的同时如何避免出现Retain Cycle问题?

10

如何以正确的方式向由属性强制定义的NSMutableArray中添加对象。

[tapBlockView setTapBlock:^(UIImage* image) {
   [self.myImageArray addObject:image]; // self retain cycle
}

如果我想创建弱引用,就像这样:

__weak NSMutableArray *array = self.myImageArray;
[tapBlockView setTapBlock:^(UIImage* image) {    [array addObject:image]; // If I will do this then how will I update original Array ?
}

我也尝试过

__weak id weakSelf = self;
[tapBlockView setTapBlock:^(UIImage* image) {
    [weakSelf storeImageInaNewMethod:image]; // Calling SToreImageInaNewMethod
}

-(void)storeImageInaNewMethod:(UIImage*)image {
   [self.myImageArray addObject:image]; // This again retaining cycle
}

如何正确更新由属性定义的原始对象?


块就像函数指针。当你不再需要它时,你能不能将块设置为nil? - Ramy Al Zuhouri
4个回答

15

在Maddy的回答之后 - 这段内容来自于2012年WWDC有关GCD和异步编程的讲座:

__weak MyClass *weakSelf = self;

[tapBlockView setTapBlock:^(UIImage* image) {
    __strong MyClass *strongSelf = weakSelf;
    if(strongSelf) {
        [strongSelf.myImageArray addObject:image];
    }
}];

我不明白为什么你又要改成__strong?我想这段代码已经足够了吧?[weakSelf.myImageArray addObject:image]; - Tariq
6
为了保证当块的第一行被执行时,如果weakSelf仍然存在,它会继续存活到块的执行结束,所以需要将其重新转换为__strong - Carl Veazey
如果你打开了警告,那么你就会知道为什么需要__strong:弱变量可能会在任何时候消失,包括在调用weakSelf.myImageArray的过程中,这肯定会引起麻烦。 - gnasher729

9
尝试使用第二种和第三种方法的组合。
__weak id weakSelf = self;
[tapBlockView setTapBlock:^(UIImage* image) {    [weakSelf.myImageArray addObject:image];
}

请注意,仅当您在块的第一行使用weakSelf时,此代码才有效。如果您首先执行其他操作,则需要使用Kaan的答案。 - malhal

1
在您的情况下,您只需要引用由self引用的数组,因此:
NSMutableArray *array = self.myImageArray;
[tapBlockView setTapBlock:^(UIImage* image)
                          {
                             [array addObject:image]; // No cycle
                          }];

只要self.myImageArray在不同的时间不返回不同的数组引用,它就可以正常工作。没有循环:当前对象引用了数组和块,反过来块引用了数组。

如果self.myImageArray在不同的时间返回不同的数组引用,则使用对self的弱引用,即您的第3种情况。


0

你的第二个和第三个看起来是正确的。第二个之所以有效,是因为你没有创建数组的副本,所以它仍然指向原始数组。第三个之所以有效,是因为对self的引用是弱引用。


第二个只有在self.myImageArray返回一个直接引用ivar时才有效。这可能不是一个安全的假设。 - rmaddy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接