我想在 Swift 中有一个返回 Bool
的函数,但如果发生异常,它也可以 throw
。
例如:
func doSomething(value: Int) throws -> Bool {
if (value > 0) {
return true
} else if (value == 0) {
throw NSError(domain: "SwiftClass", code: 0, userInfo: nil)
}
return false
}
这在 Swift 中运行良好,但如果我尝试在 Objective-C 中使用此函数,编译器将无法找到该方法。我知道 throws
需要将 Objective-C 函数签名更改为 doSomething:x error:&error
并且如果我将返回类型更改为 Void
-
func doSomething(value: Int) throws -> Void {
if (value == 0) {
throw NSError(domain: "SwiftClass", code: 0, userInfo: nil)
} else if (value < 0) {
throw NSError(domain: "SwiftClass", code: -1, userInfo: nil)
}
}
但这有不同的语义。在第一个示例中,我只需要在出现问题时处理异常(或非 nil NSError
)。使用此代码,我必须捕获异常(或检查错误)并确定它是真正的问题还是只是有效的“错误”情况。
真的不可能使用带有非 void 返回并在 Objective-C 上下文中抛出的 Swift 函数吗?
最佳答案
如我的评论所述,我不清楚为什么这不起作用。 documentation没有给出任何建议这不应该起作用,但它也没有明确说明它应该起作用。我对文档的阅读表明它应该有效。
话虽如此,我们可以通过将返回类型更改为 Void
并使用 inout< 将其包装在一个可从 Objective-C 调用的方法中
结果参数:
func doSomething(value: Int) throws -> Bool {
if (value > 0) {
return true
} else if (value < 0) {
return false
} else {
throw NSError(domain: "SwiftClass", code: 0, userInfo: nil)
}
}
func doSomething(value: Int, inout result: Bool) throws {
do {
result = try doSomething(value)
} catch let error {
// If need be, assign some default value to result.
throw error
}
}
或者,根据您的评论,如果我们返回一个可以桥接到 Objective-C 类(显然不包括 Bool
)的值,编译器似乎会很高兴,所以我们可以这样包装:
@objc func doSomething(value: Int) throws -> NSNumber {
do {
return try doSomething(value)
} catch let error {
throw error
}
}
在尝试这个过程中,很清楚为什么只有当我们返回一个可以映射到 Objective-C 类的值时它才有效。
编译器不会让您从标有@objc
和throws
的方法返回可选值。为什么?因为在 Swift 端,我们使用 try
语义来调用该方法,而在 Objective-C 中这种方法是完全不同的。 nil
用于表示失败。
因此尝试在 Swift 中创建一个带有this 签名的方法:
@objc func doSomething(value: Int) throws -> NSNumber?
生成此警告:
Throwing method cannot be marked @objc because it returns a value of optional type 'NSNumber?'; 'nil' indicates failure to Objective-C
虽然最后,我仍然非常建议您将 Swift 方法编写为具有返回 Bool
的签名并编写一个返回 NSNumber
的包装方法,以便我们仍然有我们的 Swift 方法,它具有尽可能准确的类型。
此外,如果您注意到,Bool
可以愉快地自动装箱到 NSNumber
中。我的包装器方法被编写为返回类型 NSNumber
,但我包装的方法返回类型 Bool
,但 Swift 非常乐意返回 Bool
来自应该返回 NSNumber
的方法。最有可能的问题是,默认情况下,如果未指定,Swift 的 Bool
会转换为 Objective-C 的 BOOL
,这是一个非类。
如果您的返回类型是 BOOL
,Objective-C 将无法区分这三种可能的情况。 BOOL
方法只有两种可能的返回值:YES
或 NO
。通过将 Bool
映射到 NSNumber
,它可以返回 @YES
、@NO
和 nil
.
如果是我,NSNumber
对我来说还不够严格。我可能会被鼓励为此编写自己的包装类。
@objc class BooleanObject: NSObject, BooleanType {
let boolValue: Bool
init(_ boolValue: Bool) {
self.boolValue = boolValue
}
}
请注意,BooleanType
协议(protocol)意味着 Swift 仍然非常乐意使用这种类型的变量,就好像它们是常规的 Bool
一样。
let b = BooleanObject(true)
if b {
// b's boolValue property is true
}
关于objective-c - 无法调用从 Obj-C 抛出并返回非 void 的 Swift 类中的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36672777/