我在ObjC/C中有这个代码:
AVCaptureFocusMode GetFocusModeWithString(NSString *mode) {
if ([mode isEqualToString:@"locked"]) {
return AVCaptureFocusModeLocked;
} else if ([mode isEqualToString:@"auto"]) {
return AVCaptureFocusModeAutoFocus;
} else {
@throw [NSError errorWithDomain: @"FocusError", code: 12];
}
}
当从ObjC代码调用时,它曾经工作得很好。现在我用swift重写调用方。然而,在swift中,这段代码实际上不会抛出:
// does not work, swift thinks this function does not throw.
do {
try GetFocusModeWithString(@"auto")
}
我做错了什么吗?ObjC代码不好吗?我怎样才能改善ObjC代码与swift很好地工作?
Objective C没有像Swift那样的do/try/catch语义。
@throw
导致运行时异常。这不是你可以在Swift中捕捉到的。
将Cocoa错误处理与Swift集成的方法在Swift Objective C互操作性文档中有描述,这个答案
首先声明你的Objective-C函数接受一个指向NSError
实例的指针。然后您可以使用__attribute__((swift_error(nonnull_error)))
标记该参数的函数。
当函数返回
时,如果错误非空,将导致Swift异常。- (AVCaptureFocusMode) getFocusModeWithString:(NSString *) mode error: (NSError **)error __attribute__((swift_error(nonnull_error))); {
*error = nil;
if ([mode isEqualToString:@"locked"]) {
return AVCaptureFocusModeLocked;
} else if ([mode isEqualToString:@"auto"]) {
return AVCaptureFocusModeAutoFocus;
}
*error = [NSError errorWithDomain:@"FocusError" code:12 userInfo:nil];
return -1;
}
现在,在你的Swift代码中你可以用
来调用它do {
let focusMode = try getFocusMode(with: "auto")
} catch {
print(error)
}
注意这将改变你在Objective-C中的方法签名;您需要将&error
传递给该方法,并在返回时检查其值。
Objective-C异常与Swift不兼容。苹果公司是这么说的:
在Objective-C中处理异常
在Objective-C中,异常不同于错误。Objective-C异常处理使用
@try
,@catch
和@throw
语法来指示不可恢复的程序员错误。这与上面描述的Cocoa模式不同,后者使用后面的NSError
参数来指示您在开发期间计划的可恢复错误。在Swift中,你可以从使用Cocoa的错误模式传递的错误中恢复,如上面的Catch errors中所述。然而,在Swift中没有从Objective-C异常中恢复的安全方法。要处理Objective-C异常,编写在异常到达任何Swift代码之前捕获异常的Objective-C代码。