Duck
Duck

Reputation: 35933

ivar is inside two blocks

I have an ivar like this declared on interface:

BOOL controllerOK;

I have to use this ivar inside a block that resides itself in a block. Something like

myBlockl = ^(){
  [self presentViewController:controller
    animated:YES
    completion:^(){
      if (controllerOK)
        [self doStuff];
      }];
};

If I try to do that, I see a warning:

capturing self strongly in this block is likely to lead to a retain cycle

for the if (controllerOK) line.

This does not appear to be one of those blocks problems that you create another variable using __unsafe_unretained before the block starts. First because this instruction cannot be used with a BOOL and second because the ivar controllerOK has to be tested on runtime inside the block. Another problem is that the block itself is declared on the interface, so it will be used outside the context where it is being created.

How do I solve that?

Upvotes: 2

Views: 385

Answers (6)

John Estropia
John Estropia

Reputation: 17500

controllerOK implicitly compiles as self->controllerOK because it needs to access its memory location through self. Because of that, it is "one of those blocks problems", although in this case just a simple BOOL variable will do.

__weak typeof(self) weakSelf = self;
myBlockl = ^(){
    BOOL isControllerOK = controllerOK;
    [self presentViewController:controller animated:YES completion:^(){
        if (isControllerOK)
        {
            [weakSelf doStuff];
        }
    }];
};

I put _weak there because even if you fix the warning message for controllerOK, you'll get it again in [self doStuff]

Upvotes: 1

rmaddy
rmaddy

Reputation: 318774

This should work:

__weak id this = self;
myBlockl = ^(){
  [self presentViewController:controller
    animated:YES
    completion:^(){
      if (this->controllerOK)
        [this doStuff];
      }];
};

Upvotes: 2

Rob
Rob

Reputation: 437381

You need to replace references to your objects with weak references.

The typical fix is to declare a local variable:

__weak id weakSelf = self;

As rmaddy's observed, referring to an ivar, controllerOK, also generates a strong reference cycle. You can replace BOOL controllerOK ivar with an object:

NSNumber *controllerOK;

and then you can use a weak reference to that, such as in the following:

controllerOK = @YES;

__weak typeof(self) weakSelf = self;
__weak NSNumber *weakControllerOk = controllerOK;

myBlockl = ^(){
    [weakSelf presentViewController:controller
                           animated:YES
                         completion:^(){
                             if ([weakControllerOk boolValue])
                                 [weakSelf doStuff];
                         }];
};

Upvotes: 0

Duck
Duck

Reputation: 35933

unfortunately the only solution that worked was to convert BOOL controllerOK to a property nonatomic, assign and then use it inside the block.

I have tested all solutions you have posted here, without success.

Upvotes: -1

matt
matt

Reputation: 534895

The problem may be that you are not in fact quoting your actual code. I tried your code and it compiled under ARC with no warning. But I had to modify it a little because your syntax for declaring a block is wrong. Thus you clearly did not copy and paste your actual code. It is a waste of time for people to try to help you if you don't show the real code that is giving trouble.

Upvotes: 0

iOS_Developer
iOS_Developer

Reputation: 183

can you try like this

myBlockl = ^(){

    [self presentViewController:controller
                       animated:YES
                     completion:^(BOOL isFinished){
                                if (isFinished == controllerOK)
                                      [self doStuff];
                                  }];
};

I am not very familiar about blocks but it worked for me.....

Upvotes: -1

Related Questions