可以在没有__weak对象(ios5 + ARC)的块中通过[self - anyFunction]

时间:2022-02-07 14:21:14

Is it possible to pass [self anyFunction] in blocks without a __weak object from self?

在没有弱对象的情况下,是否有可能在块中传递[self anyFunction] ?

As an example this is valid code from the System Framework:

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

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

You can pass [self anyFunction] in the completion block without a warning. But if you write your own method with a completion block, the following warning occurs: capturing 'self' strongly in this block is likely to lead to a retain cycle.

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

A working solution is quite simple (iOS 5 + ARC). Before the block declare:

一个有效的解决方案非常简单(ios5 + ARC)。块前声明:

__weak MyClass *weakSelf = self;

and in the completion block you have to call:

在完成模块中你必须调用:

[weakSelf anyFunction];

But, back to my Question: Why there is no need in the System Framework APIs to use a __weak object and to use self without any warnings. And how to implement a method without the need of a __weak object in the block?

但是,回到我的问题:为什么在系统框架api中不需要使用__weak对象和使用self而不需要任何警告。如何实现一个方法而不需要块中的__weak对象?

Thank you for your effort.

谢谢你的努力。

2 个解决方案

#1


53  

The blocks which throw up the error are ones where you capture the objects that own the block. For example

抛出错误的块是您捕获拥有该块的对象的块。例如

[object performBlock:^{
    [object performSomeAction]; // Will raise a warning
}];

or

[self performBlock:^{
    [self doSomething];    // Will raise a warning
}];

but

[self performBlock:^{
    [object doSomething];    // <-- No problem here
}];   

Because an object retains its blocks, and a block retains it's objects. So in both these cases, the object which performs the block owns the block, which also owns the object. So you have a loop - a retain cycle. which means the memory is leaked.

因为对象保留它的块,而块保留它的对象。在这两种情况下,执行block的对象拥有block, block也拥有对象。所以你有一个循环,一个保持循环。这意味着内存泄漏了。

In the example you have given - you're looking at a class method. You're calling the block on a UIView class, not a UIView object. A class has no memory associated with it. And you are probably calling this function from a controller, so the self reference is being retained by the block, but there is no loop because self is not retaining the block.

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

In the same way that, you may have noticed, not all objects that are used in the block need to be weakly referenced - just the ones that cause a retain cycle.

同样地,您可能已经注意到,并不是块中使用的所有对象都需要弱引用—只有引起保留循环的对象才需要弱引用。

#2


14  

On code that I need to compile potentially with or without ARC, or with or without the newer compilers, I do the following ... functionally it's the same as what you've listed already, but it avoids the__weak and also avoids the retain release cycles:

对于需要使用或不使用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


53  

The blocks which throw up the error are ones where you capture the objects that own the block. For example

抛出错误的块是您捕获拥有该块的对象的块。例如

[object performBlock:^{
    [object performSomeAction]; // Will raise a warning
}];

or

[self performBlock:^{
    [self doSomething];    // Will raise a warning
}];

but

[self performBlock:^{
    [object doSomething];    // <-- No problem here
}];   

Because an object retains its blocks, and a block retains it's objects. So in both these cases, the object which performs the block owns the block, which also owns the object. So you have a loop - a retain cycle. which means the memory is leaked.

因为对象保留它的块,而块保留它的对象。在这两种情况下,执行block的对象拥有block, block也拥有对象。所以你有一个循环,一个保持循环。这意味着内存泄漏了。

In the example you have given - you're looking at a class method. You're calling the block on a UIView class, not a UIView object. A class has no memory associated with it. And you are probably calling this function from a controller, so the self reference is being retained by the block, but there is no loop because self is not retaining the block.

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

In the same way that, you may have noticed, not all objects that are used in the block need to be weakly referenced - just the ones that cause a retain cycle.

同样地,您可能已经注意到,并不是块中使用的所有对象都需要弱引用—只有引起保留循环的对象才需要弱引用。

#2


14  

On code that I need to compile potentially with or without ARC, or with or without the newer compilers, I do the following ... functionally it's the same as what you've listed already, but it avoids the__weak and also avoids the retain release cycles:

对于需要使用或不使用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;
}];