调用块内的块后的 BAD ACCESS (iOS)
Posted
技术标签:
【中文标题】调用块内的块后的 BAD ACCESS (iOS)【英文标题】:BAD ACCESS after block within a block is called (iOS) 【发布时间】:2015-02-07 23:20:24 【问题描述】:我有一个块,我正在从 firebase 检查用户的状态属性。如果状态属性是“免费”,我想从块中返回,否则我想搜索另一个用户并检查他们的状态,直到找到一个“免费”用户:
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);
];
如果块不需要被召回并且第一个被检查的用户已经“空闲”,那么一切都很好。我不知道为什么会出现此错误/崩溃,并且想知道如何解决它!
谢谢!
【问题讨论】:
在 checkIfFree 中复制 comp 块: 我该怎么做? myCompletion copyBlock= [compblock 复制]; 【参考方案1】: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
对自身有很强的引用。【参考方案2】:
我认为你仍然可能有一个错误,因为你所有的块都是在堆栈上创建的。因此,如果发生任何异步事件,myResponseBlock 将消失。
我建议您将 myResponse 块复制(使用带有 copy 属性的属性)到属性中并从那里重用它。这样你的块就在堆上,当 self 设置为 nil 时就消失了。
【讨论】:
以上是关于调用块内的块后的 BAD ACCESS (iOS)的主要内容,如果未能解决你的问题,请参考以下文章
单例 iOS 中 removeFromSuperview 上的 EXC_BAD_ACCESS