Swiftでプロトコルを定義し、Delegateを作成することで、Delegateパターンの使用方法を学びます。
Delegate パターンは、Delegation とも呼ばれ、Swift コードや Apple ライブラリで頻繁に見られるアーキテクチャパターンです。この記事では、Delegation の概要と、Swift でカスタム delegate を作成する例を紹介します。
- Swift の Delegate パターン
- デリゲートプロトコルの作成
- デリゲートプロトコルを拡張する
- カスタムデレゲートの実装
- カスタムデレゲートを使用する方法
- オプションのデリゲートメソッドを作成する
1. Swift の Delegate パターン
Delegateという名前は、制御を委譲する(他の何かに制御を与える)という概念に由来しています。Swiftでは、デリゲートは、別のオブジェクトの動作を制御または修正するために使用できる、定義されたインターフェイスを持つコントローラオブジェクトです。
1つの例は、iOSアプリの UIApplicaitonDelegate です。iOS システムは、UIApplicaitonDelegate を使用して、プッシュ通知の受信、 URL を開く、アプリケーションを起動するなどの iOS の動作を変更します。
2. デリゲートプロトコルの作成
カスタムデリゲートを作成するための最初のステップは、デリゲートプロトコルを作成することです。プロトコルは、カスタムデリゲートが実装しなければならないインターフェース、変数と関数のセットです。
// ViewActionDelegateというカスタムプロトコルを定義する
protocol ViewActionDelegate {
// 期待されるデリゲート変数を定義する
var state: ViewState { get }
var userID: String? { get set }
// 期待されるデリゲートブロックの定義
var errorHandler: ((Error) -> Void)? { get set }
// 期待されるデリゲート関数の定義
func handle(action: ViewAction)
}
ViewActionDelegate
の定義、および以下のコード例では、ViewState
とViewAction
の列挙を使用しています。
enum ViewState {
case `default`
case loading
}
enum ViewAction {
case save
case cancel
}
3. デリゲートプロトコルを拡張する
デリゲートは、他の Swift の型と同様に、計算変数と関数を追加するために拡張することができます。
// ViewActionDelegate を拡張する
extension ViewActionDelegate {
// 計算変数の定義
var isReadyForNextAction: Bool {
return state != .loading
}
}
4. カスタムデレゲートの実装
次のステップは、カスタムデリゲートViewActionDelegate
に準拠したクラスまたは構造体を作成することです。まず、class や struct を定義し、そのclass や struct を拡張してデリゲートに対応させるというのがきれいなやり方です。
// ActionController クラスの定義
class ActionController {
// デリゲートプロトコル定義に合致する変数を定義する
var state: ViewState = .default
var userID: String?
var errorHandler: ((Error) -> Void)?
}
// ActionControllerを拡張し、デリゲートに準拠させる。
extension ActionController: ViewActionDelegate {
// デリゲートプロトコル定義で要求される機能を実装する。
func handle(action: ViewAction) {
switch action {
case .save:
break
case .cancel:
break
}
}
}
5. カスタムデレゲートを使用する方法
最後に、カスタムデリゲートを使用します。この例では、ActionView
という UIView を作成し、ViewActionDelegate
を使用して動作を変更します。
以下の例では、ActionView
のオプションのデリゲート参照を使用していますが、オプションの参照は(メモリ管理の点から) weak です。
class ActionView: UIView {
// デリゲートへの参照を保持するためのオプション変数を作成します。
var delegate: ViewActionDelegate?
// デリゲートのhandle(action:)の実装に基づいて、saveの動作を変更する。
@IBAction func save() {
guard let delegate = delegate else { return }
guard delegate.isReadyForNextAction else { return }
delegate.handle(action: .save)
}
// デリゲートの errorHandler に基づいて handle(error:) の動作を変更する。
func handle(error: Error) {
delegate?.errorHandler?(error)
}
}
ActionView
のdelegate
プロパティを使って動作を変更することで、カスタムデリゲートの実装は完了します。ここでは、ActionController
をカスタマイズして、ActionView
のdelegate
プロパティに割り当てている。
class ActionViewController: UIViewController {
var actionView = ActionView()
var actionController = ActionController()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// actionController の設定
actionController.userID = "@robert"
actionController.errorHandler = { (error) in
// ハンドルエラー
}
// actionViewのデリゲートとしてactionControllerをアサインします。
actionView.delegate = actionController
}
}
6. オプションのデリゲートメソッドを作成する
Objective-C のデリゲートは、オプションのメソッドを持つことができます。Swift では、@objc
修飾子を使用して、プロトコルを Objective-C のプロトコルとしてマークすることができます。プロトコルを @objc
としてマークした後、特定のプロトコル関数を @objc
でマークすることができ、マークした関数上でoptional
修飾子を使用することができます。
// Swiftで@objcデリゲートを定義する
@objc protocol ViewActionDelegate {
// オプションのデリゲート関数を作成する
@objc optional func ignoreActions() -> Bool
}
オプションのデリゲートメソッドを実装し、アプリケーションで呼び出すことができます。
if delegate.ignoreActions?() == true {
// ハンドルケース
}
Swiftでカスタムデリゲートを実装する
以上です。デリゲーションを使用し、Swift でカスタムデリゲートを作成することで、オブジェクトの動作をカスタマイズし、アプリの複雑さをよりよく管理することができます。