iOSの開発をしていると、UIViewControllerと同名のStoryboardを用意しておいて、UIViewControllerを生成するコードがよく書くと思います。
let storyboard = UIStoryboard(name: "SampleViewController", bundle: nil)
let viewController = storyboard.instantiateInitialViewController() as! SampleViewController
覚えてしまえば簡単なコードですが 出来れば共通化したいところです。
共通化
そこで Swift 2.0 から追加された「protocol extension」を使って、UIViewControllerにその能力を与えられるようにしてみました。
具体的には、以下のようにプロトコルを採用するだけでその能力が得られるようにしてみました。
// ViewControllerの定義
class SampleViewController: UIViewController, StoryboardInitializable {
}
// 生成
let viewController = SampleViewController.instantiateStoryboard()
仕組み
以下のようにプロトコルとその拡張を用意することで実現しています。
protocol StoryboardInitializable {
}
extension StoryboardInitializable where Self: UIViewController {
static func instantiateStoryboard() -> Self {
let type = Mirror(reflecting: self).subjectType
let name = String(type).componentsSeparatedByString(".")[0] // クラス名を取得
let storyboard = UIStoryboard(name: name, bundle: nil)
let viewController = storyboard.instantiateInitialViewController() as! Self
return viewController
}
}
Xibからの生成にも対応する
UIViewを同名のNibファイル(.xib)から生成することもよくあります。こちらも同じ仕組みで共通化してみました。
// Viewの定義
class SampleView: UIView, XibInitializable {
}
// 生成
let view = SampleView.instantiateXib()
protocol XibInitializable {
}
extension XibInitializable where Self: UIView {
static func instantiateXib() -> Self {
let type = Mirror(reflecting: self).subjectType
let name = String(type).componentsSeparatedByString(".")[0] // クラス名を取得
let nib = UINib(nibName: name, bundle: nil)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! Self
return view
}
}
全てのUIViewController/UIViewに適用する
プロトコルの採用すら省略したい、という場合には以下のようにUIViewController/UIViewをextensionで拡張することで何も書かずともStoryboard/xibから生成する能力を得られます。
extension UIViewController : StoryboardInitializable {
}
extension UIView : XibInitializable {
}
// 何も書かかなくても使えるようになる
let viewController = SampleViewController.instantiateStoryboard()
let view = SampleView.instantiateXib()
ただしこうした場合、同名のStoryboard/xibから生成することを意図していないクラスに対しても呼べてしまうので注意が必要です。(が、実際に不都合が起こるケースは稀かと思います)
まとめ
- UIViewControllerで
StoryboardInitializable
プロトコルを採用すると、同名のStoryboardから生成する能力を得られます - UIViewで
XibInitializable
プロトコルを採用すると、同名のNibファイル(.xib)から生成する能力を得られます - Swift 2.0 から導入された「protocol extensions」は便利!
コード全体:
https://github.com/YusukeHosonuma/SwiftCommons/blob/master/SwiftCommons/ResourcesInitializable.swift
SwiftCommons
Swiftの勉強用として作り始めた共通ライブラリです。発展途上ですが、MITライセンスですのでよろしければご利用ください。
https://github.com/YusukeHosonuma/SwiftCommons