我希望在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
)。使用此代码,我必须捕获异常(或检查错误)并确定它是真正的问题还是只是有效的“假”情况。
是否真的不可能使用具有在Objective-C上下文中抛出的非void返回的Swift函数?
答案 0 :(得分:5)
正如我的评论中所述,我不清楚为什么这不应该起作用。 documentation没有任何建议表明这不应该有效,但它也没有明确说明应该这样做。我阅读文档说它应该有用。
话虽如此,我们可以将此包装在一个可从Objective-C调用的方法中,方法是将返回类型更改为Void
并使用inout
参数结果:
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中使用此签名创建一个方法:
@objc func doSomething(value: Int) throws -> NSNumber?
生成此警告:
投掷方法无法标记为@objc,因为它返回的值为可选类型&#39; NSNumber?&#39 ;; &#39;零&#39;表示没有达到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
协议意味着Swift仍然非常乐意使用此类型的变量,就像它们是常规Bool
一样。
let b = BooleanObject(true)
if b {
// b's boolValue property is true
}