Swift:delegate(デリゲートパターン)の使い方とサンプルコード

アプリ制作に必須な知識にも関わらず、なかなかわかりづらい delegate ですが、一度覚えてしまえば、何が分からなかったのかが分からないくらい分かりやすいデザインパターンであることに気づきます。

今回はこの delegate について分かりやすく説明してみたいと思います。

デリゲートパターンについて

デリゲートパターンでできる事は、delegate の意味の通り、ViewController(あるクラス) の処理を、別の ViewController(あるクラス) へ任せる事です。

もっと厳密に言えば、あるクラスに実装している処理を、そのクラスのインスタンスを生成している別のクラス(ViewController)側で処理したい場合にデリゲートパターンを使用します。

次項で具体的な使い方を見て行きたいと思います。

デリゲートパターンの使い方

使用例として、デリゲートパターンを使用し MainViewController 内の SpriteKit シーンファイル MainScene から MainViewController へ、シーンがタッチされたことを通知したいと思います。

大まかな流れは以下のようになります。

  1. MainScene クラスを作成しプロトコルを実装する
  2. MainScene クラスからデリゲートメソッドを呼ぶ
  3. MainViewController に MainScene クラスのデリゲート(委譲)を宣言する
  4. MainViewController に MainScene クラスのプロトコルで定義したデリゲートメソッドを実装する

MainScene クラスを作成しプロトコルを実装する

MainScene.swift を作成し、touchesBegan をオーバライドします。

import SpriteKit

class MainScene: SKScene {

    override func didMoveToView(view: SKView) {
        
    }
    
    // Add touchesBegan 
    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        
    }
}

MainScene.swift の先頭にプロトコルを記述し、mainSceneDelegate をクラス内で宣言します。

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) {

    }
}

MainScene クラスからデリゲートメソッドを呼ぶ

touchBegan からデリゲートメソッドを呼びます。

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()
    }
}

MainViewController に MainScene クラスのデリゲート(委譲)を宣言する

class MainViewController: UIViewController の後にカンマで区切り、MainSceneDelegate を追加します。

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)
    }
}

MainViewController に MainScene クラスのプロトコルで定義したデリゲートメソッドを実装する

viewDidLoad() の下に sceneTouched() を実装します。

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!")
    }
}

結果

ビルドし、表示された画面(MainScene)をタッチすると MainViewController の sceneTouched() が呼ばれているのが確認できます。

デリゲートパターンサンプル

上記 MainViewController.swift と MainScene.swift のサンプルコードです。

MainViewController.swift

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!")
    }
}

MainScene.swift

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()
    }
}

まとめ

ViewController 間の値の受け渡し方法は、AppDelegate 内でグローバル変数を使用する方法等がありますが、delegate パターンを使用すれば、クラス内でなにが行われているかを意識することなく、クラスで処理された結果を受け取ることができます。

クラスはクラス内での役割(処理)を、クラスのインスタンスを生成した側ではクラスで行われた処理の結果を使ってどうするか、といった役割分担が分かりやすく記述できるため、コードの可読性が上がりメンテナンスが容易になります。

最初はどこにプロトコルを書くのか考えたり、どっちにデリゲートメソッドを書くのかを混同しがちですが、デリゲートパターンの意図を理解できれば、自然と使いこなせるようになります。

デリゲートパターンを使って、誰が見ても分かりやすいコーディングを心がけたいと思います。

この記事がみなさんのお役に立ちましたら、下記「Share it」よりブックマークやSNSで共有していただければ幸いです。

siro:chro 無料ゲーム SQN をリリースしました

img_sqn_00

sirochro 初の無料ゲームアプリ SQN をリリースしました。
記事:SQN: iOS 無料ゲームアプリ SQN - Sequential Numbers をリリース
ちょっとした時間に楽しめる完全無料のゲームなっていますので、是非ダウンロードして遊んでみてください。

↓SQN のダウンロードはこちらから

Related Contents

Pickup Contents