アプリ制作に必須な知識にも関わらず、なかなかわかりづらい delegate ですが、一度覚えてしまえば、何が分からなかったのかが分からないくらい分かりやすいデザインパターンであることに気づきます。
今回はこの delegate について分かりやすく説明してみたいと思います。
デリゲートパターンについて
デリゲートパターンでできる事は、delegate の意味の通り、ViewController(あるクラス) の処理を、別の ViewController(あるクラス) へ任せる事です。
もっと厳密に言えば、あるクラスに実装している処理を、そのクラスのインスタンスを生成している別のクラス(ViewController)側で処理したい場合にデリゲートパターンを使用します。
次項で具体的な使い方を見て行きたいと思います。
デリゲートパターンの使い方
使用例として、デリゲートパターンを使用し MainViewController 内の SpriteKit シーンファイル MainScene から MainViewController へ、シーンがタッチされたことを通知したいと思います。
大まかな流れは以下のようになります。
- MainScene クラスを作成しプロトコルを実装する
- MainScene クラスからデリゲートメソッドを呼ぶ
- MainViewController に MainScene クラスのデリゲート(委譲)を宣言する
- MainViewController に MainScene クラスのプロトコルで定義したデリゲートメソッドを実装する
MainScene クラスを作成しプロトコルを実装する
MainScene.swift を作成し、touchesBegan をオーバライドします。
[code]
import SpriteKit
class MainScene: SKScene {
override func didMoveToView(view: SKView) {
}
// Add touchesBegan
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
}
}
[/code]
MainScene.swift の先頭にプロトコルを記述し、mainSceneDelegate をクラス内で宣言します。
[code]
import SpriteKit
// Add Protocol
protocol MainSceneDelegate {
func sceneTouched()
}
class MainScene: SKScene {
// Add
var mainSceneDelegate: MainSceneDelegate?
override func didMoveToView(view: SKView) {
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
}
}
[/code]
MainScene クラスからデリゲートメソッドを呼ぶ
touchBegan からデリゲートメソッドを呼びます。
[code]
import SpriteKit
protocol MainSceneDelegate {
func sceneTouched()
}
class MainScene: SKScene {
var mainSceneDelegate: MainSceneDelegate?
override func didMoveToView(view: SKView) {
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
// Send to delegate method
mainSceneDelegate?.sceneTouched()
}
}
[/code]
MainViewController に MainScene クラスのデリゲート(委譲)を宣言する
class MainViewController: UIViewController の後にカンマで区切り、MainSceneDelegate を追加します。
[code]
import UIKit
import SpriteKit
class MainViewController: UIViewController, MainSceneDelegate {
var skView: SKView?
var mainScene: MainScene!
override func viewDidLoad() {
super.viewDidLoad()
mainScene = MainScene(size: self.view.bounds.size)
mainScene.mainSceneDelegate = self
self.skView = self.view as? SKView
self.skView!.presentScene(mainScene)
}
}
[/code]
MainViewController に MainScene クラスのプロトコルで定義したデリゲートメソッドを実装する
viewDidLoad() の下に sceneTouched() を実装します。
[code]
import UIKit
import SpriteKit
class MainViewController: UIViewController, MainSceneDelegate {
var skView: SKView?
var mainScene: MainScene!
override func viewDidLoad() {
super.viewDidLoad()
mainScene = MainScene(size: self.view.bounds.size)
mainScene.mainSceneDelegate = self
self.skView = self.view as? SKView
self.skView!.presentScene(mainScene)
}
// Add delegate method
func sceneTouched() {
println(“SceneTouched!”)
}
}
[/code]
結果
ビルドし、表示された画面(MainScene)をタッチすると MainViewController の sceneTouched() が呼ばれているのが確認できます。
デリゲートパターンサンプル
上記 MainViewController.swift と MainScene.swift のサンプルコードです。
MainViewController.swift
[code]
import UIKit
import SpriteKit
class MainViewController: UIViewController, MainSceneDelegate {
var skView: SKView?
var mainScene: MainScene!
override func viewDidLoad() {
super.viewDidLoad()
mainScene = MainScene(size: self.view.bounds.size)
mainScene.mainSceneDelegate = self
self.skView = self.view as? SKView
self.skView!.presentScene(mainScene)
}
func sceneTouched() {
println(“SceneTouched!”)
}
}
[/code]
MainScene.swift
[code]
import SpriteKit
protocol MainSceneDelegate {
func sceneTouched()
}
class MainScene: SKScene {
var mainSceneDelegate: MainSceneDelegate?
override func didMoveToView(view: SKView) {
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
mainSceneDelegate?.sceneTouched()
}
}
[/code]
まとめ
ViewController 間の値の受け渡し方法は、AppDelegate 内でグローバル変数を使用する方法等がありますが、delegate パターンを使用すれば、クラス内でなにが行われているかを意識することなく、クラスで処理された結果を受け取ることができます。
クラスはクラス内での役割(処理)を、クラスのインスタンスを生成した側ではクラスで行われた処理の結果を使ってどうするか、といった役割分担が分かりやすく記述できるため、コードの可読性が上がりメンテナンスが容易になります。
最初はどこにプロトコルを書くのか考えたり、どっちにデリゲートメソッドを書くのかを混同しがちですが、デリゲートパターンの意図を理解できれば、自然と使いこなせるようになります。
デリゲートパターンを使って、誰が見ても分かりやすいコーディングを心がけたいと思います。
この記事がみなさんのお役に立ちましたら、下記「Share it」よりブックマークやSNSで共有していただければ幸いです。