1. ホーム
  2. ios

[解決済み] Swiftのプロトコルでオプションのメソッドを定義するには?

2022-03-25 08:15:52

質問

Swiftで可能ですか?もし不可能なら、それを行うための回避策はあるのでしょうか?

どのように解決するのですか?

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 は、このプロトコルに準拠することができます。構造体、列挙型、関連型は不可。

  • オプションのメソッドが実装されているかどうかを常に確認する必要があります。 をオプションで呼び出すか、適合する型がそれを実装しているかどうかをチェックすることで、実装されています。これは、オプショナルメソッドを頻繁に呼び出す場合、多くの定型句を導入することになるかもしれません。