まとめ
Custom View / Custom ViewController どちらの場合も、 Storyboard とコードの両方から扱うためには、 View や ViewController そのものを xib で定義するのではなくて root view を xib で定義してinstantiate するのが良さそうです。
Custom View
まず MyView.xib を作成し、ルートの view の下に UI 部品を配置していきます。 このとき、ルートの view は MyView クラスではなく UIView のままです。
次に、 File's Owner に MyView クラスを設定します。 すると MyView.xib と MyView クラスが紐付けられ、 UI 部品の Outlet や Action を接続できるようになります。
MyView クラスでは、ルートになる UIView を MyView.xib から生成し、 addSubview します。
Storyboard から生成された場合 ( init(coder:)
) とコードから生成された場合 ( init(frame:)
) のどちらで初期化された場合でも
同じように処理されるようにします。
import Foundation import UIKit class MyView: UIView { required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) instantiateView() } override init(frame: CGRect) { super.init(frame: frame) instantiateView() } private func instantiateView() { // MyView.xib からインスタンスを生成し、 IBOutlet / IBAction を self と接続する let nib = UINib(nibName: "MyView", bundle: .main) let rootView = nib.instantiate(withOwner: self).first as! UIView // 生成した rootView の位置とサイズを self にぴったり合わせて addSubview rootView.frame = self.bounds self.addSubview(rootView) } @IBOutlet weak var label: UILabel! @IBAction func buttonDidTouch(_ sender: Any) { // do something } }
Custom ViewController
MyViewController.xib を作成し、ルートの view の下に UI 部品を配置していきます。 ルートを UIViewController ではなく UIView にするのがポイントです。
次に、 File's Owner に MyViewController クラスを設定します。 すると MyViewController.xib と MyViewController クラスが紐付けられ、 UI 部品の Outlet や Action を接続できるようになります。
MyViewController クラスでは、 loadView()
をオーバーライドして、
MyViewController.xib から生成した UIView を self.view に設定します。
import Foundation import UIKit class MyViewController: UIViewController { override func loadView() { // MyViewController.xib からインスタンスを生成し root view に設定する let nib = UINib(nibName: "MyViewController", bundle: .main) self.view = nib.instantiate(withOwner: self).first as! UIView } @IBOutlet weak var label: UILabel! @IBAction func buttonDidTouch(_ sender: Any) { // do something } }
出典: