Xcodeには、Interface Builder
でコードを書かずにデザインを構築することが多いと思います
Auto Layoutも比較的付けやすいので、使ったことがない人はいないくらい使われると思っています
今回は、Interface Builder
とソースコードを紐付ける方法をまとめます。(主に初期化などです)
ViewController
まずはViewControllerについてです。
ViewControllerの作り方についてですが、 New File... から新しいViewControllerのクラスを作ります。
次に、利用するStoryboardに新しいViewControllerを置き、 Storyboard ID
に適当な文字列を指定します。
また、ソースコードでViewControllerを作った際にはClass
に対応するクラスを指定しましょう。
インスタンス化する場合には下記のように行います。
let vc = storyboard?.instantiateViewController(identifier: "( Storyboard IDで指定した名前)") as? ViewController(該当のViewController)
今まで説明したものは1つのStroryBoardで管理する場合の方法ですが、1つのViewControllerを1つのStroryBoardで管理する場合には下記のようの行います。
let sb = UIStoryboard(name: "( Storyboardの名前)", bundle: nil) let vc = storyboard?.instantiateViewController() as? ViewController(該当のViewController)
UIStoryboardのイニシャライザの引数について、 name には.storyboardファイルの拡張子を除いた部分の文字列を、 bundle には指定した.storyboardファイルとそれに関連するリソースが含まれているbundleを渡します。
上のコードのようにbundleにnilを渡すと、このメソッドはmain bundle
を見にいきます。
XibでのカスタムView
ViewControllerをXibで定義するパターンもありますが、ここではカスタムViewをxibで作成するパターンについて説明します
カスタムViewを作成(初期化)する方法は大まかに2種類あるので、それぞれ説明します
①File’s Ownerで設定する場合
下記のようにカスタムViewをXibで作成する場合にFile’s Ownerでクラス指定する場合です。
生成方法は、イニシャライザでxibファイルを読み込み、自身に addSubview() します。
CustomViewクラスを継承したRoot viewの上に通常のUIViewを一枚挟んでから、Interfce Builder上で配置した部品が載ることになるのでパフォーマンスに影響を与える可能性があります(微々たるものではないので影響はほぼなさそう)
class LoginForm: UIView { @IBOutlet private weak var loginButton: UIButton! override init(frame: CGRect) { super.init(frame: frame) loadNib() } required init?(coder: NSCoder) { super.init(coder: coder) loadNib() } private func loadNib() { let view = UINib(nibName: "LoginForm", bundle: nil).instantiate(withOwner: self, options: nil).first as! UIView view.frame = self.bounds addSubview(view) } }
②Custom Classで設定する場合
File’s Ownerとは別の方法でCustom Classで設定する方法もあります。
Custom Classで設定する場合には、File’s Ownerで設定する場合とは違い、無駄なUIViewを挟む必要はありません。
しかし、コードでinit(frame:)
が呼ばれてしまうと、その時点でCustomViewがインスタンス化されてしまうため、xibと結びつけることができません。
コードから呼び出す場合には別途 static関数などを用意し、そちらを利用する必要があります。
仮にload() の処理をrequired init?(coder: NSCoder)で実行した場合には初期化されているのにinstantiate
でサイド初期化しようとして無限ループに陥ります。
class LoginForm: UIView { @IBOutlet private weak var loginButton: UIButton! required init?(coder: NSCoder) { super.init(coder: coder) } // パラメータを渡す場合にもここで引数を設定してViewController側で呼び出す static func load() { let view = UINib(nibName: "LoginForm", bundle: nil).instantiate(withOwner: nil, options: nil).first as! Self addSubview(view) } }
File’s OwnerとCustom Classで設定する方法がありますが、File’s Ownerで設定する方がUIViewを扱う時と同じ方法で使えるのでおすすめです。
まとめ
ここまでUIのインスタンス化について記載しました。 どのパターンを使うのかは実装方法やインスタンス化のコードを踏まえ、自分のプロジェクトにあったものを採用するのがいいでしょう。