iOS
Swift

Protocolを利用してStoryboardやXibファイルからインスタンスを生成する

More than 3 years have passed since last update.

追記

iOS - 構造体でStoryboardとNibを管理する - Qiitaの方が1箇所にリソースの定義をまとめられて分かりやすいかもしれません。


Swift - StoryboardやXibファイルからインスタンスを生成するprotocol - Qiitaという記事を拝見して、そのProtocolを改造した。

protocol Instantiatable {

typealias InstanceType
static func instantiateFromResource(resourceName: String?, identifier: String?) -> InstanceType!
}

protocol ResourceBundleProvider {
static var resourceBundle: NSBundle { get }
}
extension ResourceBundleProvider {
static var resourceBundle: NSBundle { return NSBundle.mainBundle() }
}

protocol StoryboardInstantiatable: Instantiatable, ResourceBundleProvider {
typealias InstanceType = Self
static var storyboardName: String { get }
static var viewControllerIdentifier: String? { get }
}
extension StoryboardInstantiatable {
static var storyboardName: String { return "" }
static var viewControllerIdentifier: String? { return nil }
static func instantiateFromResource(resourceName: String? = nil, identifier: String? = nil) -> InstanceType! {
let name = resourceName ?? storyboardName
let identifier = identifier ?? viewControllerIdentifier

let storyboard = UIStoryboard(name: name, bundle: resourceBundle)
if let identifier = identifier {
return storyboard.instantiateViewControllerWithIdentifier(identifier) as! InstanceType
} else {
return storyboard.instantiateInitialViewController() as! InstanceType
}
}
}

protocol NibInstantiatable: Instantiatable, ResourceBundleProvider {
typealias InstanceType = Self
static var nibName: String { get }
}
extension NibInstantiatable {
static var nibName: String { return "" }
static func instantiateFromResource(resourceName: String? = nil, identifier: String? = nil) -> InstanceType! {
let name = resourceName ?? nibName
let nib = UINib(nibName: name, bundle: resourceBundle)
return nib.instantiateWithOwner(nil, options: nil).first as! InstanceType
}
}


使い方


StoryboardInstantiatableの使い方

UIViewControllerをStoryboardInstantiatableに以下のように適合させる。storyboardNameというクラス変数にストーリーボード名を設定するだけ。instantiateメソッドにストーリーボード名を直接渡す場合はstoryboardNameは必要ない。

class SampleViewController: UIViewController, StoryboardInstantiatable {

static var storyboardName = "Sample"

インスタンスを得るには以下のようにする。instantiateにストーリーボード名を渡すと、そのストーリーボードが利用される。Storyboard名を渡すとstoryboardNameが設定されていても引数のStoryboard名が優先されて利用される。

Storyboard ID(引数名: identifier)を渡すと、instantiateViewControllerWithIdentifier(_)でインスタンス化が行われる。指定しないとviewControllerIdentifierクラス変数が利用される。引数でもクラス変数でもidentifierが指定されない場合はinstantiateInitialViewController()が利用される。

let controller = SampleViewController.instantiateFromResource()

let controllerInOtherStoryboard = SampleViewController.instantiateFromResource("Other")
let controllerWithIdentifier = SampleViewController.instantiateFromResource("Other", identifier: "SecondViewController")


NibInstantiatableの使い方

UIViewをNibInstantiatableに以下のように適合させる。nibNameというクラス変数にNib名を設定するだけ。ただし変数の型は明示する必要がある。Storyboardと同様にinstantiateメソッドにストーリーボード名を直接渡す場合はnibNameは必要ない。

class SampleView: UIView, NibInstantiatable {

static var nibName = "SampleView"

インスタンスを得るには以下のようにする。

let sampleView = SampleView.instantiateFromResource()

let sampleViewOnOtherNib = SampleView.instantiateFromResource("OtherView")