没有检查块

时间:2014-01-14 06:02:15

标签: ios objective-c objective-c-blocks

我有一个执行异步网络调用的方法,然后通过块传递成功或失败结果:

- (void) loginWithSuccess:(void (^)(id responseObject))success failure:(void (^)(NSError* error))failure {
...
  if(error) {
    failure(error);
  }
  else {
    success(responseObject);
  }
}

我注意到,如果我调用此方法并传入nil作为我的块,我的应用程序将崩溃EXEC_BAD_ACCESS

[manager loginWithWithSuccess:nil failure:nil];

但是,如果我传入空块,它运行正常:

[manager loginWithWithSuccess:^(id responseObject){} failure:^(NSError *error){}];

我认为这是因为在运行时你无法将参数传递给nil?因此,在定义采用块的方法时,我应该在调用它们之前始终检查块是否为nil?

2 个答案:

答案 0 :(得分:3)

只看Apple的Frameworks,一些带有块参数的方法接受NULL/nil作为块参数(例如animateWithDuration:animations:completion:),其他方法则不接受(例如enumerateObjectsUsingBlock:)。

如果您正在设计API,则必须做出决定。如果没有块有意义,你应该接受nil并在执行块之前检查,否则你应该抛出像[@[] enumerateObjectsUsingBlock:nil]那样的断言:

'NSInvalidArgumentException', reason: '*** -[NSArray enumerateObjectsUsingBlock:]: block cannot be nil'

那你为什么要EXEC_BAD_ACCESS

当调用一个块时,你正在取消引用该地址,如果它没有指向一个实际的块,你显然不能这样做。 this answer中有一个很好的解释。

答案 1 :(得分:0)

请尝试以下示例来了解调用块逻辑:

void (^printString)(NSString*) = ^(NSString* arg) {
    NSLog(@"%@", arg);
};

//(1) printString = ^(NSString* arg){};
//(2) printString = NULL;

printString(@"1");

在控制台中,您将看到" 1"。然后取消注释(1)和控制台显示"被叫"但没有错误! 最后,取消注释(2)并获取EXEC_BAD_ACCESS。这完全是你的情况。

被调用的块必须不是NULL或nil。您需要在调用之前检查loginWithSuccess中是否存在传递块。