2015-01-07 4 views
9

Swiftには抽象メソッドがないため、デフォルトの実装で無条件にエラーが発生するメソッドを作成しています。これにより、サブクラスは抽象メソッドをオーバーライドします。関数が値を返すことが期待され、上記の機能は一切return文を持っていない、コンパイルが失敗しているので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() 
    } 
} 

問題:私のコードは次のようになります。私はこの関数が常にエラーを発生させるため、実行を完了できないことをコンパイラーに知らせるために何らかの方法が必要です。

どのようにエラーハンドリングがすべてライブラリレベルと思われるので、コンパイラの理解を超えて、Swiftでこれを行うことができますか?プログラムの実行を(うまくいけば正常に)終了するための言語レベルの機能はありますか?

+0

解決策を使用して質問に自己回答したが、悪い/間違った問題を解決しようとしています。 Swiftには抽象メソッドが組み込まれていない理由があります。 – nhgrif

答えて

20

スウィフトの@noreturn属性は関数とメソッドを呼び出し元に戻さないようにマークします。

のように、おそらく最も簡単な例として、組み込み関数abort()年代のシグネチャは次のとおりです。

@noreturn func abort() 

これは、コンパイラにそれが必要なすべての情報を提供します。例えば、以下はうまくコンパイルします:alwaysFail()が理論的にIntを返しますが

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

を、スウィフトはabort()が呼び出された後に実行を継続することができないことを知っています。

NSException.raiseは、事前スウィフト方式なので、@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()を使用することができます。 Xcodeの8ベータ6(スウィフト3ベータ6)あなたが今いることを示すために、代わりに@noreturnNever戻り値の型を使用することができますでは

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 
} 
2

プロトコルを作成してshouldBeOverriddenを必須の方法にしてから、そのプロトコルに準拠させることで、よりうまくいくと思います。 https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

+0

これはうまくいくかもしれませんが、SuperClassの共有実装を使って実装するのが最も良い、SuperClassのすべてのサブクラスの他の要素があります。特に、私の「サブクラス」(またはあなたの提案に従うプロトコルに準拠したクラス)が持つ必要のあるいくつかの格納されたプロパティがあり、すべての単一のサブクラスでこれらを再宣言する必要はありません。 – SelectricSimian

+2

私は2つのアプローチを組み合わせ、プロトコルと基本クラスを組み合わせることをお勧めします。抽象メソッドはObjective-CやSwiftではあまり一般的ではなく、プロトコルがより良い選択ではないケースは見つかっていません。アップルは、この組み合わせの手法を時折使用します(UIBarPositioningを参照)。 –

+1

これで十分です。ちょっと冗長に見えますが、意味があり、きれいです。 – SelectricSimian

8

extensionを使用して、以前のオプションは、実際にこれを行うためだけの抽象化です関数が呼び出し元に返されません。

func crash() -> Never { 
    fatalError("Oops") 
} 
関連する問題