デリゲーションパターンは、Swiftエコシステムにおける重要なパターンの一つで、オブジェクト間でイベント処理の責任を伝達するために広く使用されます。デリゲーションは、クラスが自身の一部の動作を別のオブジェクト(通常はプロトコルで定義されるデリゲート)に委任することを可能にします。
protocol DataUpdateDelegate: AnyObject { func didUpdateData(_ data: String) } class DataProvider { weak var delegate: DataUpdateDelegate? func updateData() { // ... データ更新のロジック delegate?.didUpdateData("新しいデータ") } } class ViewController: UIViewController, DataUpdateDelegate { func didUpdateData(_ data: String) { print("データが更新されました: \(data)") } }
weak(またはunowned)であるべきです。これによりretain cycleを避けます。AnyObjectから継承されます。デリゲートがvalue type(例えば、struct)である場合、どのようにデリゲーションを実装しますか?
回答:
Swiftにおいて、デリゲートは必ず参照型(classまたはAnyObject)でなければなりません。なぜなら、weak参照に許可されるのは参照型だけだからです。デリゲートがstructやenumであることはできません。そうすると問題が発生します。コンパイラはweakプロパティの使用を許可せず、strong参照はretain cycleを引き起こします。
// エラー!デリゲートをstructとして宣言することはできません:コンパイラはそれをweakにすることを許可しません protocol StructDelegate { ... } struct MyStructDelegate: StructDelegate { ... } weak var delegate: StructDelegate? // エラー
歴史
あるプロジェクトで、デリゲートのプロパティがweakとしてマークされるのを忘れました。その結果、viewとデリゲートの間にretain cycleが発生し、アプリケーションは徐々にメモリを「膨らませ」、30分後にはクラッシュしました。
歴史
デリゲートがvalue type(struct)を介して実装され、クラスとして機能するべきIBOutletは通知を受け取らず、全く接続されませんでした。問題はログの分析とデバッグによってのみ発見されました。
歴史
プロジェクトで、デリゲートプロトコルがAnyObjectから継承されておらず、デリゲートのプロパティがweak varとして宣言されていました。これによりコンパイラエラーが発生し、チームが理解し修正するのに時間がかかりました。