1. ホーム
  2. ios

[解決済み] プロトコルは、SelfまたはassociatedTypeの要件を持つため、一般的な制約としてのみ使用できる

2022-06-25 10:30:23

質問

RequestTypeというプロトコルがあり、以下のようなassociatedTypeモデルを持っています。

public protocol RequestType: class {

    associatedtype Model
    var path: String { get set }

}

public extension RequestType {

    public func executeRequest(completionHandler: Result<Model, NSError> -> Void) {
        request.response(rootKeyPath: rootKeyPath) { [weak self] (response: Response<Model, NSError>) -> Void in
            completionHandler(response.result)
            guard let weakSelf = self else { return }
            if weakSelf.logging { debugPrint(response) }
        }
    }

}

今度は、失敗したすべてのリクエストのキューを作ろうとしています。

public class RequestEventuallyQueue {

    static let requestEventuallyQueue = RequestEventuallyQueue()
    let queue = [RequestType]()

}

しかし、次の行でエラーが発生します。 let queue = [RequestType]() は、プロトコルRequestTypeはSelfまたはassociatedTypeの要件を持つため、ジェネリック制約としてのみ使用できる、というエラーが発生します。

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

とりあえず、プロトコルを調整して、関連する型を使用するルーチンを追加したとします。

public protocol RequestType: class {
    associatedtype Model
    var path: String { get set }

    func frobulateModel(aModel: Model)
}

そして、Swift では、配列として RequestType を好きなように作成できるようになったとします。 それらのリクエストタイプの配列を関数に渡すことができました。

func handleQueueOfRequests(queue: [RequestType]) {
    // frobulate All The Things!

    for request in queue {
       request.frobulateModel(/* What do I put here? */)
    }
}

全部をフロブル化したいというところまではわかったのですが、呼び出しに渡す引数の種類を知る必要があります。 私のいくつかの RequestType エンティティは LegoModel を取るものもあれば PlasticModel を取ることもできますし、他の人は PeanutButterAndPeepsModel . Swift はこの曖昧さに不満なので、関連する型があるプロトコルの変数を宣言させません。

同時に、それは例えば、配列を作成することは完全に理にかなっています RequestType の配列を作成することは非常に理にかなっています。 LegoModel . これは合理的に見えますし、実際そうなのですが、それを表現する何らかの方法が必要なのです。

そのための一つの方法は、抽象的なモデルの型名に実際の型を関連付けるクラス(または構造体、enum)を作成することです。

class LegoRequestType: RequestType {
  typealias Model = LegoModel

  // Implement protocol requirements here
}

の配列を宣言するのは全く合理的です。 LegoRequestType というのは、もし私たちが frobulate を渡す必要があるからです。 LegoModel を毎回渡す必要があります。

連想型のこのニュアンスは、それらを使用する任意のプロトコルを特別なものにします。Swift 標準ライブラリはこのようなプロトコルを持ちますが、最も顕著なのは Collection または Sequence .

を実装したものを配列として作成できるようにする。 Collection プロトコルを実装した配列やシーケンスプロトコルを実装したセットを作成できるように、標準ライブラリは "型消去"という技術を採用して、構造体型である AnyCollection<T> または AnySequence<T> . 型消しのテクニックはStack Overflowの回答で説明するにはかなり複雑ですが、Webを検索すればそれに関する記事がたくさんあります。

のビデオをお勧めします。 Alex Gallagher による PAT (Protocols With Associated Types) についてのビデオです。 をYouTubeで見ることができます。