可以在没有__weak对象的块中传递[self anyFunction](iOS 5 + ARC)

时间:2012-01-25 13:36:32

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

是否可以在没有__weak对象的块中传递[self anyFunction]?

作为示例,这是来自系统框架的有效代码:

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

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

工作解决方案非常简单(iOS 5 + ARC)。在块声明之前:

__weak MyClass *weakSelf = self;

在完成程序段中,您必须致电:

[weakSelf anyFunction];

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

感谢您的努力。

2 个答案:

答案 0 :(得分: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 :(得分: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;
}];