调用块内的块后的 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

为啥 scala 函数中的块变量在执行内部块后无法更新?

尝试获取 Documents 文件夹 URL 的 BAD_ACCESS 异常

在带有其他命令的块内时退出 /b 无法正常工作

地理围栏 iOS 崩溃 EXC_BAD_ACCESS

iOS 崩溃 - 异步 UIImageView setImage EXC_BAD_ACCESS