Aurelien Porte
Aurelien Porte

Reputation: 2702

How to execute block inside another block (w/o bad access)

One of my methods (mySecondMethod) receives a block and need to add an additional treatment to this block before passing it as an argument to another method. Here is the code sample:

- (void)myFirstMethod {
    // some code
    __weak MyController *weakSelf = self;
    [self mySecondMethod:^(BOOL finished) {
        [weakSelf doSomething:weakSelf.model.example];
    }];
}

- (void)mySecondMethod:(void(^)(BOOL finished))completion {
    void (^modifiedCompletion)(BOOL) = ^void(BOOL finished){
        completion(finished);
        _messageView.hidden = YES; //my new line
    };
    [UIView animateWithDuration:duration animations:^{
        //my code
    } completion:modifiedCompletion];
}

When run, I got a bad access error on completion(finished) line. completion is NULL. I tried to copy the block like this:

void (^copiedCompletion)(BOOL) = [completion copy];
void (^modifiedCompletion)(BOOL) = ^void(BOOL finished){
    copiedCompletion(finished);
    _messageView.hidden = YES; // my new line
};

but still got the error.

When I empty out completion block, the crash still happen so the crash is not due to what is inside.

Any idea how to solve this? Thanks!

Upvotes: 1

Views: 2745

Answers (1)

sbarow
sbarow

Reputation: 2819

I think you are getting the bad access because of this

// some code
__weak MyController *weakSelf = self;
[self mySecondMethod:^(BOOL finished) {
    [weakSelf doSomtehing:weakSelf.model.example];
}];

Try changing it to.

id example = self.model.example;
[self mySecondMethod:^(BOOL finished) {
    [self doSomething:example];
}];

Edit

The block needs to be copied before being called.

Side Note

Do a check before calling blocks to avoid unexpected crashes.

if (completion) {
   completion(finished);
}

Upvotes: 1

Related Questions