Swift プロトコルでオプションのメソッドを宣言するにはどうすればよいでしょうか? 質問する

Swift プロトコルでオプションのメソッドを宣言するにはどうすればよいでしょうか? 質問する

Swift で可能ですか? できない場合は回避策はありますか?

ベストアンサー1

1. デフォルトの実装を使用する (推奨)。

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        /* return a default value or just leave empty */
    }
}

struct MyStruct: MyProtocol {
    /* no compile error */
}

利点

  • Objective-C ランタイムは使用されません(少なくとも明示的には使用されません)。つまり、構造体、列挙型、非NSObjectクラスをこれに準拠させることができます。また、強力なジェネリック システムを活用できることも意味します。

  • このようなプロトコルに準拠する型に遭遇した場合、すべての要件が満たされていることを常に確信できます。常に具体的な実装かデフォルトの実装のいずれかです。これは、他の言語での「インターフェース」または「コントラクト」の動作です。

デメリット

  • 要件以外の場合Void、適切なデフォルト値を設定する必要がありますが、これは必ずしも可能ではありません。ただし、この問題が発生した場合は、そのような要件には実際にはデフォルトの実装がないか、API 設計中に間違いを犯したことを意味します。

  • 少なくとも、特別な戻り値を使用してその問題に対処しない限り、デフォルトの実装とまったく実装されていない実装を区別することはできません。次の例を検討してください。

    protocol SomeParserDelegate {
        func validate(value: Any) -> Bool
    }
    

    単に返すだけのデフォルト実装を提供する場合true、一見すると問題ありません。では、次の疑似コードを考えてみましょう。

    final class SomeParser {
        func parse(data: Data) -> [Any] {
            if /* delegate.validate(value:) is not implemented */ {
                /* parse very fast without validating */
            } else {
                /* parse and validate every value */
            }
        }
    }
    

    このような最適化を実装する方法はありません。デリゲートがメソッドを実装しているかどうかを知ることはできません。

    この問題を克服する方法はいくつかありますが (オプションのクロージャの使用、異なる操作に対する異なるデリゲート オブジェクトの使用など)、この例では問題が明確に示されています。


2. を使用します@objc optional

@objc protocol MyProtocol {
    @objc optional func doSomething()
}

class MyClass: NSObject, MyProtocol {
    /* no compile error */
}

利点

  • デフォルトの実装は必要ありません。オプションのメソッドまたは変数を宣言するだけで準備完了です。

デメリット

  • すべての準拠型が Objective-C 互換であることを要求するため、プロトコルの機能が大幅に制限されます。つまり、NSObjectそのようなプロトコルに準拠できるのは、 を継承するクラスのみです。構造体、列挙型、関連型はありません。

  • オプション メソッドが実装されているかどうかを、オプションで呼び出すか、準拠する型が実装しているかどうかを確認することによって、常に確認する必要があります。オプション メソッドを頻繁に呼び出す場合は、これにより大量の定型コードが発生する可能性があります。

おすすめ記事