调用块内块后的不良访问(iOS)

我有一个块,我正在从firebase检查用户的状态属性。 如果status属性是'free',我想从块中返回,否则我想search另一个用户并检查他们的状态,直到find'free'用户:

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]; 

如图所示,当在下面的“compblock(YES)”行中第二次调用该块时,出现“BAD ACCESS”错误:

 -(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); }]; } 

一切都很好,如果该块不必被召回,并检查的第一个用户已经“免费”。 我被困在为什么我得到这个错误/崩溃,并想知道我可以如何解决它!

谢谢!

一个block捕获包括它自己在内的所有variables,然而variablesmyResponseBlock还没有在块内被初始化。 正因为如此,你调用checkIfFree方法的nil值,从而导致应用程序崩溃。

你可以做的一件事就是将你的块声明为__blockvariables。

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

另外,请注意块保留所有传递给它们的variables。 在这种情况下,你在块内保留自己 ,所以只要块执行,它就不会被释放。 所以,除非另有要求,否则总是将弱引用传递给块。

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

我想你仍然可能有一个错误,因为所有的块都在堆栈上创build。 所以如果发生任何asynchronous,myResponseBlock将会消失。

我推荐的是你的副本(使用具有副本属性的属性)你的myResponse块到一个属性,并从那里重用。 这样,当你的自我被设置为零时,你的块就会在堆上消失。