【Swift】Delegateメソッドでジェネリクスを使いたい時にassociatedtypeは使えない


はじめに

今回は、Protocolにジェネリクスを引数に受け取るメソッドを定義したとき、
そのProtocolに書いたメソッドをDelegateメソッドとして、使いたい場合の書き方を記事にしました。

前提条件

Swiftにおける下記の3点について知っていること

  • Protocol
  • Delegate
  • ジェネリクス

このように書くとコンパイルエラーになる

ソースコード

protocol SampleDelegate: AnyObject {
    associatedtype T
    func getSampleData(_ data: T)
}

class Fuga: SampleDelegate {
    typealias T = String
    func getSampleData(_ data: T) {
        print(data)
    }
}

class Hoge {
    weak var delegate: SampleDelegate?     // コンパイルエラー
}

エラーの内容

Protocol 'SampleDelegate' can only be used as a generic constraint because it has Self or associated type requirements
自分が実装していたときは、このエラーが出ました。
もしかしたら、この記事を見ていただいている方の中で、このエラーが出ている方がいるかも知れません。

和訳すると、
「プロトコルは、Selfまたは関連する型の要件があるため、一般的な制約としてのみ使用することができる」
とのことですが、これだけではよくわかりませんでした。

associatedtypeFuga側でtypealias T = Stringというように、Stringに型決めしたところで、
delegateを持つ側のHogeは、実際に処理を行うクラスが持っている型を知らないのでコンパイルエラーになってしまうと自分は解釈しました。

こうすればコンパイルが通る

protocol SampleDelegate: AnyObject {
    func getSampleData<T>(_ data: T)
}

class Fuga: SampleDelegate {
    func getSampleData<T>(_ data: T) {
        print(data)
    }
}

class Hoge {
    weak var delegate: SampleDelegate?
}

問題点を1つ上げるとすれば、コンパイルエラーのときは、Fuga側で、型付けをすることができましたが、
今回は、associatedtypeが使えないため、残念ながら型を確定させてあげることができません。

なので、そのあたりは、func getSampleData<T>(_ data: T)で考慮してあげる必要がありそうです。

以上!