我有一个执行异步网络调用的方法,然后通过块传递成功或失败结果:
- (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?
答案 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中是否存在传递块。