在iOS 5及以上版本的ARC环境下,是否可以在块中传递[self anyFunction]而不使用__weak对象?

23

在不使用self的__weak对象的情况下,是否可以在块中传递[self anyFunction]?

以下是系统框架中有效的示例代码:

[UIView animateWithDuration:0.8 animations:^{
            //Do animationStuff
        } completion:^(BOOL finished) {
            [self anyFunction];
 }];

您可以在完成块中传递[self anyFunction]而不会出现警告。但是,如果您使用完成块编写自己的方法,则会出现以下警告:在此块中强烈捕获 'self' 可能导致保留循环

一个可行的解决方案非常简单(iOS 5 + ARC)。在块之前声明:

__weak MyClass *weakSelf = self;

在完成块中,您必须调用:

[weakSelf anyFunction];

但是,回到我的问题:为什么在系统框架API中不需要使用__weak对象并且可以在不产生任何警告的情况下使用self。如何在块中实现无需__weak对象的方法?

感谢您的努力。

2个回答

53

引发错误的代码块是那些捕获拥有该代码块的对象的代码块。例如:

[object performBlock:^{
    [object performSomeAction]; // Will raise a warning
}];
或者
[self performBlock:^{
    [self doSomething];    // Will raise a warning
}];

但是

[self performBlock:^{
    [object doSomething];    // <-- No problem here
}];   
因为一个对象保留其块,而一个块保留它的对象。所以,在这两种情况下,执行块的对象拥有块,而块也拥有对象。所以你有了一个循环 - 一个保留循环,这意味着内存泄漏。

在你提供的例子中,你正在查看一个类方法。你正在调用一个UIView类上的块,而不是UIView对象。一个类没有与之关联的内存。而且你可能正在从控制器中调用这个函数,所以self引用被块保留,但是没有循环,因为self没有保留该块。

同样地,您可能已经注意到,并不是所有在块中使用的对象都需要弱引用 - 只有会导致保留循环的那些对象需要弱引用。


1
谢谢,我的问题已经得到澄清。 在我的情况下,拥有该块的对象是一个 ivar,因此您必须使用一个 self__weak 对象。但是当我在使用块的函数中声明对象时,可以传递 self 而不需要一个 __weak 的对象。这很有道理。再次感谢。 - andreschneider
1
我发现 [self.ivar performBlock:^{ [self doSomething]; }]; 会导致编译器警告,而 [self performBlock:^{ [self doSomething]; }]; 则不会导致编译器警告。 - Jesse Armand
也许 [self performBlock:^{ [self doSomething];}]; 应该被替换为 [self performBlock:^{ [self doSomething]; self=nil;} ]; - dklt

14

我需要编译的代码可能需要启用或禁用ARC,也可能使用较新或较旧的编译器。我的做法是… 从功能上讲,它与您已经列出的内容相同,但它避免了__weak并且还避免了保留释放循环:

//
// FOR NON-ARC PROJECTS
//
__block __typeof__(self) bself = self;
[someObject doThingWithBlock:^(id result){
    if (!bself)
        return;
    bself.thingWhich = result;
}];

///
// FOR ARC PROJECTS
//
__weak MyClass *bself = self;
[someObject doThingWithBlock:^(id result){
    if (!bself) 
        return;
    bself.thingWhich = result;
}];

1
在 ARC 下,这可能会导致保留循环。(__block 语义已更改以保留对象。) - Jonathan Sterling
没错。我们现在使用__weak修饰的MyClass *bself = self; - Greg Combs
添加了弧形示例,以及我的异步块错误处理。 - Greg Combs

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