BAD ACCESS 在一个块内的块被调用后 (iOS)
BAD ACCESS after block within a block is called (iOS)
我有一个块,我在其中检查来自 firebase 的用户状态 属性。如果状态 属性 是 'free' 我想从块中 return ,否则我想搜索另一个用户并检查他们的状态并这样做直到 '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);
}];
}
如果不需要撤回该区块并且检查的第一个用户已经是 'free',则一切都很好。我不知道为什么会收到这个 error/crash 并想知道如何解决它!
谢谢!
A block
捕获传入的所有变量,包括其自身,但是变量 myResponseBlock
尚未在块内初始化。因此,您使用 nil
值调用 checkIfFree
方法,这反过来导致应用程序崩溃。
您可以做的一件事就是将您的块声明为 __block
变量。
__block __weak void(^weakResponseBlock)(BOOL);
void(^myResponseBlock)(BOOL);
weakResponseBlock = myResponseBlock = ^void(BOOL finished) {
...
if (weakResponseBlock) {
[self checkIfFree:weakResponseBlock];
}
}
此外,请注意块会保留传递给它们的所有变量。在这种情况下,您将 self 保留在块内,因此只要块执行,它就永远不会被释放。因此,除非另有要求,否则始终将弱引用传递给块。
__weak UIViewController *weakSelf = self;
weakResponseBlock = myResponseBlock = ^void(BOOL finished) {
...
if (weakResponseBlock) {
[weakSelf checkIfFree:weakResponseBlock];
}
}
我认为您仍然可能会出错,因为您的所有块都是在堆栈上创建的。因此,如果发生任何异步,myResponseBlock 将消失。
我推荐的是将您的副本(使用带复制属性的 属性)将您的 myResponse 块放入 属性 并从那里重新使用它。这样你的块就存在于堆上并在 self 设置为 nil 时消失。
我有一个块,我在其中检查来自 firebase 的用户状态 属性。如果状态 属性 是 'free' 我想从块中 return ,否则我想搜索另一个用户并检查他们的状态并这样做直到 '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);
}];
}
如果不需要撤回该区块并且检查的第一个用户已经是 'free',则一切都很好。我不知道为什么会收到这个 error/crash 并想知道如何解决它!
谢谢!
A block
捕获传入的所有变量,包括其自身,但是变量 myResponseBlock
尚未在块内初始化。因此,您使用 nil
值调用 checkIfFree
方法,这反过来导致应用程序崩溃。
您可以做的一件事就是将您的块声明为 __block
变量。
__block __weak void(^weakResponseBlock)(BOOL);
void(^myResponseBlock)(BOOL);
weakResponseBlock = myResponseBlock = ^void(BOOL finished) {
...
if (weakResponseBlock) {
[self checkIfFree:weakResponseBlock];
}
}
此外,请注意块会保留传递给它们的所有变量。在这种情况下,您将 self 保留在块内,因此只要块执行,它就永远不会被释放。因此,除非另有要求,否则始终将弱引用传递给块。
__weak UIViewController *weakSelf = self;
weakResponseBlock = myResponseBlock = ^void(BOOL finished) {
...
if (weakResponseBlock) {
[weakSelf checkIfFree:weakResponseBlock];
}
}
我认为您仍然可能会出错,因为您的所有块都是在堆栈上创建的。因此,如果发生任何异步,myResponseBlock 将消失。
我推荐的是将您的副本(使用带复制属性的 属性)将您的 myResponse 块放入 属性 并从那里重新使用它。这样你的块就存在于堆上并在 self 设置为 nil 时消失。