Swift调用OC含NSError方法的两个问题:异常捕获与返回值缺失
问题背景
我定义了如下Objective-C类:
@interface TestModel : NSObject - (BOOL)test1:(NSError * _Nullable * _Nullable)error; - (int)test2:(NSError * _Nullable * _Nullable)error; @end @implementation TestModel - (BOOL)test1:(NSError * _Nullable * _Nullable)error { return YES; } - (int)test2:(NSError * _Nullable * _Nullable)error { if (error) { *error = [NSError errorWithDomain:@"domain" code:0 userInfo:nil]; } return 9; } @end
随后我在Swift中这样调用:
@objcMembers @objc public class Utils: NSObject { func test() { do { let value = try TestModel().test1() print("success value: \(value)") } catch { print("failed error: \(error)") } var error: NSError? let value = TestModel().test2(&error) print("value>>>>>> \(value)") } }
运行后得到结果:
success value: () value>>>>>> 9
我有两个技术疑问:
- 为什么调用test1时需要通过try-catch捕获异常,而调用test2时却不需要?
- 为什么调用test1后没有获取到预期的返回值?
解答
问题1:test1需要try-catch,test2不需要的原因
这是Swift对Objective-C错误处理的桥接规则导致的:
- 当Objective-C方法返回值为
BOOL,且最后一个参数是NSError **时,Swift会自动将其桥接成**抛出错误(throws)**的方法。因为Objective-C的通用约定是:BOOL返回NO代表操作失败,同时通过NSError **输出错误信息,Swift直接把这种模式映射成自身的throws错误处理机制,所以调用时必须用try配合do-catch、try?或try!。 - 而test2的返回值是
int类型,不符合Swift自动桥接成throws方法的规则。Swift会保留Objective-C原有的错误传递方式,也就是通过传入NSError?指针获取错误,因此不需要try-catch。
问题2:test1没有返回预期值的原因
还是源于Swift与Objective-C的桥接规则:
当Objective-C的BOOL返回值+NSError **参数的方法被桥接成Swift的throws方法时,原有的BOOL返回值会被忽略——Swift的throws方法约定:只要方法不抛出错误,就代表操作成功,原来的YES/NO已经被映射为“是否抛出错误”的逻辑。因此你在Swift中调用try test1()时,得到的返回值是Void(即代码中的()),而非原Objective-C方法返回的YES。
如果想在Swift中获取test1的BOOL返回值,需要修改Objective-C的方法签名,打破自动桥接成throws的规则,比如给方法添加NS_SWIFT_NOTHROW宏:
- (BOOL)test1:(NSError * _Nullable * _Nullable)error NS_SWIFT_NOTHROW;
这样Swift会将其视为普通方法,你可以像调用test2那样传入错误指针,同时获取Bool类型的返回值。
内容的提问来源于stack exchange,提问作者x_z
相关产品推荐
相关产品推荐

