BAD ACCESS after block within a block is called (iOS)

不羁岁月 提交于 2019-12-24 13:40:31

问题


I have a block where I am checking a user's status property from firebase. If the status property is 'free' I want to return from the block, otherwise I want to search for another user and check their status and do so until a 'free' user has been found:

void( ^ myResponseBlock)(BOOL finished) = ^ void(BOOL finished) {

if (finished) {
    if ([self.freedom isEqualToString: @"free"]) {
        NSLog(@"free!");
        return;
    } else if ([self.freedom isEqualToString: @"matched"]) {
        NSLog(@"get another user");
        //get another user
        do {
            //picking another random user from array
            rando = arc4random_uniform(arraycount);
        }

        while (rando == randomIndex && rando == [self.randString intValue]);
        self.randString = [NSString stringWithFormat: @"%u", rando];
        [users removeAllObjects];
        [users addObject:usersArray[rando]];
        self.freeUser = users.firstObject;

        NSLog(@"set up another check");

        //error is called after this block is called here, again
        [self checkIfFree: myResponseBlock];

    } else {
        NSLog(@"error!");
    }
} else {
    NSLog(@"not finished the checking yet");
}
};
[self checkIfFree: myResponseBlock];

As shown, I'm getting an error of 'BAD ACCESS' when the block is called for a second time on the 'compblock(YES)' line below:

-(void)checkIfFree:(myCompletion) compblock{

self.freeUserFB = [[Firebase alloc] initWithUrl:[NSString stringWithFormat: @"https://skipchat.firebaseio.com/users/%@", self.freeUser.objectId]];

[self.freeUserFB observeEventType:FEventTypeValue  withBlock:^(FDataSnapshot *snapshot)
 {
     self.otherStatus = snapshot.value[@"status"];

     NSLog(@"snapshot info %@", snapshot.value);

     if ([self.otherStatus isEqualToString:@"free"]) {
         self.userIsFree = YES;
         self.freedom = @"free";
         NSLog(@"user is free in the check method %@", self.freedom);
     }
     else{
         self.userIsFree = NO;
         self.freedom = @"matched";
         NSLog(@"user is matched in the check method %@", self.freedom);

     }
     compblock(YES);
 }];
}

Everything is fine if the block does not have to be recalled and the first user that's checked is already 'free'. I'm stuck as to why I'm getting this error/crash and wondering how I can solve it!

Thanks!


回答1:


A block captures all variables passed in including itself, however the variable myResponseBlock has not been initialized yet inside the block. Because of this, you are calling checkIfFree method with a nil value which in turn causing app to crash.

One thing you can do to overcome this would be declaring your block as a __block variable.

__block __weak void(^weakResponseBlock)(BOOL);

void(^myResponseBlock)(BOOL);

weakResponseBlock = myResponseBlock = ^void(BOOL finished) {
    ...
    if (weakResponseBlock) {
       [self checkIfFree:weakResponseBlock];
    }
}

Additionally, please note that blocks retain all variables passed into them. In this case, you are retaining self inside the block, so it will never get deallocated as long as block executes. So unless required otherwise, always pass a weak reference to blocks.

__weak UIViewController *weakSelf = self;

weakResponseBlock = myResponseBlock = ^void(BOOL finished) {
    ...
    if (weakResponseBlock) {
       [weakSelf checkIfFree:weakResponseBlock];
    } 
}



回答2:


I think still you might have an error because all your blocks are being created on the stack. So if anything async should happen the myResponseBlock will go away.

What I'd recommend is your copy (using the a property with copy attribute) your myResponse block into a property and reuse it from there. That way your block lives on the heap and goes away when self is set to nil.



来源:https://stackoverflow.com/questions/28388668/bad-access-after-block-within-a-block-is-called-ios

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!