调用块内块后的不良访问(iOS) [英] BAD ACCESS after block within a block is called (iOS)

查看:159
本文介绍了调用块内块后的不良访问(iOS)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个块,我正在从firebase检查用户的状态属性。如果status属性是'free',我想从块中返回,否则我想搜索另一个用户并检查它们的状态,直到找到'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);
//获取另一个用户
do {
//从数组$ b中选取另一个随机用户$ b $ rando = arc4random_uniform(arraycount);


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

NSLog(@设置另一个检查);

//这个块在这里被调用后调用错误
[self checkIfFree:myResponseBlock];

} else {
NSLog(@error!);

} else {
NSLog(@尚未完成检查);
}
};
[self checkIfFree:myResponseBlock];

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

   - (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(@用户匹配检查方法%@,self.freedom);


compblock(YES);
}];



$ b $ p
$ b

如果块不必被调用,第一个用户这是检查已经免费。

谢谢!

捕获包括它自己在内的所有变量,但是变量 myResponseBlock code>尚未在块内初始化。因此,您正在调用 checkIfFree 方法,其中 nil 值导致应用程序崩溃。



你可以做的一件事就是将你的块声明为 __ block 变量。

  __ block __weak void(^ weakResponseBlock)(BOOL); 

void(^ myResponseBlock)(BOOL);

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






$ b另外,请注意块保留所有传入的变量他们。在这种情况下,您在块内保留 self ,所以只要块执行,它就永远不会被释放。所以,除非另有要求,否则总是传递一个弱引用块。

  __ weak UIViewController * weakSelf = self; 

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


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!

解决方案

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

这篇关于调用块内块后的不良访问(iOS)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆