Swiftには(例えばC#のように)delegateという名称の専用機能があるわけではない。delegateは情報通知のためのデザインパターンの1つであり、Swiftおいては、慣例的にdelegateという変数名でプロパティ宣言して使うことが多い。
登場人物は情報通知元と情報通知先の2人であるが、基本的には、通知元は通知先のことを知る必要はないということがポイントであり、再利用性の高いコードのために重要な点だ。
Swiftにおけるコーディング例
環境
- Xcode 6.4
- Swift 1.2
- iOS 8.4
GitHubにはソース一式をあげておきました。
Objective-Cにおける例はこちらに書きました。
通知元(SenderViewController)
例として実装が必須なもの(required)とそうでない(optional)メソッドをそれぞれ定義している。
本来のデザインパターンの意義から考えると、個人的には、requiredよりもoptionalなメソッドのほうが有用性が高いと思っている。
requiredなメソッドについては、プロトコル適合クラス(通知先、今回の例ではReceiverViewController)において実装しないとXcodeがErrorを出して知らせてくれる。一方、optionalなメソッドについてはwarningは発生しないが、optionalについてはObjective-C互換でないと動作しないため、protocolの前に@objcディレクティブを付与する必要がある。
また、Objective-C互換ではAny型を指定できないため、AnyObject型を指定している。
import UIKit
// You need to use 'AnyObject' insted of 'Any'
// because of optional protocol and Objective-C compatible mode.
@objc protocol SenderViewControllerDelegate: NSObjectProtocol {
func senderViewController(senderViewController: SenderViewController, didSendRequiredInfo: Dictionary<String, AnyObject>)
optional func senderViewController(senderViewController: SenderViewController, didSendOptionalInfo: Dictionary<String, AnyObject>)
}
class SenderViewController: UIViewController {
weak var delegate: SenderViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - IBAction
@IBAction func goBack(sender: AnyObject) {
// Xcode checks the method is implemented or not.
self.delegate?.senderViewController(self, didSendRequiredInfo: ["message": "this is required", "score": 3])
// You do not need to check the method is implemented or not.
self.delegate?.senderViewController?(self, didSendOptionalInfo: ["message": "this is optional", "score": 100])
self.dismissViewControllerAnimated(true, completion: nil)
}
}
通知先(ReceiverViewController)
プロトコルを適合(準拠)するクラス。通知元とは逆に、通知先は通知元が提供するメソッド等をよく理解しておく必要がある。
import UIKit
class ReceiverViewController: UIViewController, SenderViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier! == "SenderView" {
let senderViewController = segue.destinationViewController as! SenderViewController
senderViewController.delegate = self
}
}
// MARK: - SenderVewControllerDelegate
func senderViewController(senderViewController: SenderViewController, didSendRequiredInfo info: Dictionary<String, AnyObject>) {
println("info: \(info)")
}
func senderViewController(senderViewController: SenderViewController, didSendOptionalInfo info: Dictionary<String, AnyObject>) {
println("info: \(info)")
}
}