Possible to pass [self anyFunction] in blocks without __weak object (iOS 5 + ARC)

10,657

Solution 1

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.

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.

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.

Solution 2

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:

//
// 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;
}];
Share:
10,657

Related videos on Youtube

andreschneider
Author by

andreschneider

I make apps.

Updated on June 06, 2022

Comments

  • andreschneider
    andreschneider almost 2 years

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

    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.

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

    __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?

    Thank you for your effort.

  • andreschneider
    andreschneider over 12 years
    Thanks, my question has been clarified. In my case the object that owns the block is an ivar, so you have to use a __weak object of self. But when I declare the object in the function where the block is used, self can passed without a __weak object of themselves. That makes sense. Thanks again.
  • Jesse Armand
    Jesse Armand almost 12 years
    What I found is [self.ivar performBlock:^{ [self doSomething]; }]; will cause a compiler warning, while [self performBlock:^{ [self doSomething]; }]; doesn't cause a compiler warning.
  • Jonathan Sterling
    Jonathan Sterling almost 12 years
    Under ARC, this might lead to a retain cycle. (__block semantics have changed to retain the object.)
  • Greg Combs
    Greg Combs almost 12 years
    That's correct. we're now using __weak MyClass *bself = self;
  • Greg Combs
    Greg Combs almost 12 years
    Added the arc example, as well as my error handling for asynchronous blocks.
  • dklt
    dklt over 11 years
    maybe [self performBlock:^{ [self doSomething];}]; should be replaced by [self performBlock:^{ [self doSomething]; self=nil;} ];