强制返回 `id` 和 inout NSError 的 Objective-C 方法桥接到可选返回

Posted

技术标签:

【中文标题】强制返回 `id` 和 inout NSError 的 Objective-C 方法桥接到可选返回【英文标题】:Force Objective-C method returning `id` and inout NSError to bridge to an optional return 【发布时间】:2018-09-18 21:48:54 【问题描述】:

考虑这个 Objective-C 类:

@interface TestAPI : NSObject

-(nullable id)aNullableMethod;

-(nullable id)aNullableMethodWithError:(inout NSError **)error;

@end

我正在使用TestAPI 作为抽象基类,并希望在 Swift 中继承它。

Swift 将此代码桥接成如下所示(即对应菜单 -> Swift 4.2 界面):

open class TestAPI : NSObject 

    open func aNullableMethod() -> Any?

    open func aNullableMethodWithError() throws -> Any

问题在于aNullableMethodWithError() 可以将nil 作为有效值返回。

如何让 Swift 相信 aNullableMethodWithError() 返回 Any? 而不是 Any

或者有没有更好的编写Objective-C方法签名的方法?

【问题讨论】:

返回nil有什么意义,如果不是“发生错误,我无法返回任何有意义的东西”? @matt - 我的示例故意简单地展示了我所看到的桥接问题。想象一个代表一个联系人的类,我想请求一个字段名称“BusinessPhoneNumber”。缺少业务电话号码不是错误,所以我想返回nil 但是在那个例子中,为什么会有一个采用NSError**的方法呢?你明白我在说什么吗?你人为地提出了一个反模式,我要求你用实际的术语来证明这一点。只要你遵守模式就没有“桥接问题”,没有理由不这样做,那么为什么不直接遵守呢? 参见***.com/q/34786115/2976878 - 导入器假定返回nil 意味着该方法抛出了错误(这就是Cocoa 约定)。如果您真的想忽略该约定,则可以使用 __attribute__((swift_error(nonnull_error))) 如 Martin 的答案底部所示来更改行为,以便如果该方法在输出中留下非零 NSError* 时被认为已抛出 -参数(从而保留返回的可选性)。 【参考方案1】:

您可能需要使用NS_SWIFT_NOTHROW:

-(nullable id)aNullableMethodWithError:(inout NSError **)error NS_SWIFT_NOTHROW;

这是导入到 Swift 中的:

open func aNullableMethodWithError(_ error: NSErrorPointer) -> Any?

如果您想将您的方法导入为throws-function,您可能需要更改方法签名以遵循约定:

返回 true 或非零(如果没有错误) 返回 false 或返回 nil 错误

类似这样的:

-(BOOL)aNullableMethod:(id*)object withError:(inout NSError **)error;

在斯威夫特中:

open func aNullableMethod(_ object: AutoreleasingUnsafeMutablePointer<AnyObject?>!) throws

【讨论】:

以上是关于强制返回 `id` 和 inout NSError 的 Objective-C 方法桥接到可选返回的主要内容,如果未能解决你的问题,请参考以下文章

无法使用类型为“(设备:AVCaptureDevice!,错误:inout NSError?)”的参数列表调用类型“AVCaptureDeviceInput”的初始化程序

如何在我的iPhone应用程序中使用NSError?

如何在 swift 函数中返回 inout(引用)?

NSError** '潜在的空取消引用.....'

无法获取 SP 的动态执行以返回 INOUT 参数

正确使用 NSError 和非 BOOL 返回函数