objective-c - 无法调用从 Obj-C 抛出并返回非 void 的 Swift 类中的方法

标签 objective-c swift exception

我想在 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 类的值时它才有效。

编译器不会让您从标有@objcthrows 的方法返回可选值。为什么?因为在 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 方法只有两种可能的返回值:YESNO。通过将 Bool 映射到 NSNumber,它可以返回 @YES@NOnil.

如果是我,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/

相关文章:

objective-c - *.h 和 *.m 文件中的两个接口(interface)

swift - cocoa swift : Error evaluateJavaScript Optional ("A JavaScript exception occurred")

swift - 为什么我的部分屏幕截图很快就模糊了?

java - string index out of bound 异常,String index out of range

ios - 在 iOS 中使用 NSFileManager 写入文件

objective-c - 在 UIImageView 中区分黑白重绘和缩放以填充模式?

java - 当 Exception 类单独可以处理所有类型的异常时,其他 Exception 类的需求是什么?

java - MySQL jdbc 驱动程序 ClassNotFoundException : com. mysql.jdbc.Driver

iphone - 名称为 SIGSEGV 且原因为 main 的 iOS 崩溃

ios - 在 Swift 中将数组元素加一