说服 Swift 由于抛出的异常,函数将永远不会返回

Convincing Swift that a function will never return, due to a thrown Exception

因为Swift没有抽象方法,我正在创建一个默认实现无条件引发错误的方法。这会强制任何子类覆盖抽象方法。我的代码如下所示:

class SuperClass {
    func shouldBeOverridden() -> ReturnType {
        let exception = NSException(
            name: "Not implemented!",
            reason: "A concrete subclass did not provide its own implementation of shouldBeOverridden()",
            userInfo: nil
        )
        exception.raise()
    }
}

问题:因为函数要return一个值,而上面的函数没有return语句,编译失败。我需要一些让编译器相信这个函数永远无法完成执行的方法,因为它总是会引发错误。

在 Swift 中,当所有错误处理似乎都是库级的,因此超出了编译器的理解范围时,如何做到这一点?是否有任何类型的语言级功能(希望优雅地)终止程序的执行?

听起来您正在做的事情会更好地通过创建一个协议并使 shouldBeOverridden 成为必需的方法,然后让您的 类 遵守该协议。 https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

Swift 的 @noreturn 属性将函数和方法标记为不返回其调用者。

作为最简单的例子,内置函数 abort() 的签名是:

@noreturn func abort()

这为编译器提供了它需要的所有信息。例如,以下将编译得很好:

func alwaysFail() -> Int {
    abort()
}

虽然alwaysFail()理论上returns一个Int,Swift知道在调用abort()后无法继续执行。

我的原始代码不起作用的原因是因为 NSException.raise 是一个 pre-Swift 方法,因此没有 @noreturn 属性。为了轻松解决这个问题,我可以使用 abort():

func shouldBeOverridden() -> ReturnType {
    println("Subclass has not implemented abstract method `shouldBeOverridden`!")
    abort()
}

或者,如果我仍然想使用 NSException,我可以定义一个具有适当属性的扩展

extension NSException {
    @noreturn func noReturnRaise() {
        self.raise()
        abort() // This will never run, but Swift will complain that the function isn't really @noreturn if I don't call a @noreturn function before execution finishes.
    }
}

作为第三种选择,我可以在 NSException.raise() 之后使用从未调用的 abort() 来安抚编译器。较早的选项,使用 extension,实际上只是执行此操作的抽象:

func shouldBeOverridden() -> ReturnType {
    let exception = NSException(
        name: "Not implemented!",
        reason: "A concrete subclass did not provide its own implementation of shouldBeOverridden()",
        userInfo: nil
    )
    exception.raise()
    abort() // never called
}

在 Xcode 8 beta 6 (Swift 3 beta 6) 中,您现在可以使用 Never return 类型而不是 @noreturn 来表示函数不会 return 给它的调用者:

func crash() -> Never {
    fatalError("Oops")
}

创建一个计算的 属性 返回一个名为 abstractoverrideMe 或类似的 Never 怎么样,像这样:

   var abstract: Never { fatalError("Must be overridden") }

用法示例:

class AbstractTableViewCell: UITableViewCell {
    func configure(with model: Any) { abstract }
}

final class ContactTableViewCell: AbstractTableViewCell {
    override func configure(with model: Any) { 
        /* Real implementation here */
    }
}