こんばんわ、daihaseです。
新型iPhoneが発表になって連日TLのiOS開発者がXcode9GMをいじり倒したり色々シミュレーターでアプリの動作報告をしてくれてますね。僕は特に何の役にもたたないので、今日はStoryboardの管理の仕方なんかを書いて見ました。
iOSアプリでStoryboardを使った画面遷移など皆さんどうされてるでしょうか?
各ViewControllerに毎回Storyboardから該当のViewControllerを取得し、って書いてくとIdentifierのタイプミスなど起きたり、またStoryboard上でStoryboard IDを変えた時など、宣言した各場所全て書き換えたりと大変ですよね。
そこで僕なんかはStoryboardBuilder.swiftのようなものを用意し、そこに全て宣言し管理するようにしています。
import UIKit class StoryboardBuilder: NSObject { var mainStoryboard: UIStoryboard! override init() { super.init() self.mainStoryboard = StoryboardBuilder.createRegisterStoryboard() } static var sharedInstance: StoryboardBuilder = { return StoryboardBuilder() }() class func storyboardWithIdentifier(identifier: String) -> UIStoryboard { return UIStoryboard(name: identifier, bundle: Bundle.main) } // Main.Storyboard生成 class func createRegisterStoryboard() -> UIStoryboard { return StoryboardBuilder.storyboardWithIdentifier(identifier: "Main") } // ログイン画面 func loginViewController() -> LoginViewController { return mainStoryboard.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController } // チュートリアル画面 func tutorialViewController() -> TutorialViewController { return mainStoryboard.instantiateViewController(withIdentifier: "TutorialViewController") as! TutorialViewController } // Email登録画面 func emailRegistrationViewController() -> EmailRegistrationViewController { return mainStoryboard.instantiateViewController(withIdentifier: "EmailRegistrationViewController") as! EmailRegistrationViewController } }
シングルトンになっていて、それぞれViewController上で以下のように取得するようなイメージです。
let loginViewController = StoryboardBuilder.sharedInstance.loginViewController() let navigationController = UINavigationController(rootViewController: loginViewController) UIApplication.shared.keyWindow?.rootViewController = navigationController
StoryboardBuilder.sharedInstance."呼び出したいコントローラー名" みたいに生成します。これならStoryboard上でStoryboard IDを後から変えた時とかも、StoryboardBuilder.swift内だけを修正するだけでいいですよね。
他にはもっとシンプルにするなら、.storyboardのファイル名とStoryboard IDを照らし合わせて取得する方法なんかも。
import Foundation import UIKit extension UIViewController { static func instantiateFromSelfStoryboard<T: UIViewController>(_: T.Type) -> T { return T.instantiateFromStoryboard(T.self, T.nameOfClass, T.nameOfClass) } static func instantiateFromStoryboard<T: UIViewController>(_: T.Type, _ storyboardName: String, _ identifier: String) -> T { let storyboard = UIStoryboard(name: storyboardName, bundle: nil) return storyboard.instantiateViewController(withIdentifier: identifier) as! T } }
UIViewControllerを拡張したクラスを作成。ここでコントローラー名が引数に指定されたら、それと同じ名前のStoryboardを取得し該当するViewControllerを返す、という感じです。
import Foundation extension NSObject { static var nameOfClass: String { return NSStringFromClass(self).components(separatedBy: ".").last! } var nameOfClass: String { return NSStringFromClass(type(of: self)).components(separatedBy: ".").last! } }
こちらは上のUIViewController+Extended.swiftから指定された、プロジェクト名.コントローラー名のコントローラー部分を切り出して文字列として返すクラスですね。
この2つを用意しておけば、各ViewControllerで以下のように書くだけで該当のStoryboardからViewControllerを取得出来ます。
let vc = UIViewController.instantiateFromSelfStoryboard(TutorialViewController.self)
これでTutorialViewController.storyboard上のTutorialViewController、そこからインスタンス生成出来るようになります。
今日はここまで。 それでは良いSwiftライフを〜