13
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Storyboard or Xib? Storyboard and Xib.

Last updated at Posted at 2017-10-06

日本語を勉強しています。上手く使えない場合が多いと思いますが、共有してみたいから、頑張って書きます。

この前、新規アプリを開発し始めた時、UI はコードか、Storyboard か、Xib か、どっちかで進めていくかなを考えました。

もちろん、コードで UI を実装できます、しかも数年前、コードで全ての画面を作る人が少なくない、でも、スクリーンサイズの充実化、開発ツールの進展に伴う、Auto LayoutSize Classes は誕生しました、コードで UI を実装するのは日々複雑になりました。

自分は Storyboard または Xib を使用して画面を作るのが好きだけど、やはりたまに迷う、 Storyboard と Xib どっちを選んだ方がいいですか?

Storyboard or Xib

チームの旧バージョン iOS Guidelines にあるルールは:

StoryBoard はコンフリクトしやすく、チーム開発には向いていないため、なるべく利用しない。各画面や画面部品ごとに .xib ファイルを用いる。

半分賛成半分反対。

一つの Storyboard に複数の ViewController がある場合、コンフリクトはぜったい発生しやすい、もしこの罠にはまると、めんどいことになるかもしれない、コンフリクトを解消するため、.xml を修正した経験がある人もいると思います。けれども、これは Storyboard の問題ではない、これをきっかけに Storyboard を諦めると、損になってしまうと思います。そもそも、Storyboard は Xib を置き換えるためのものではありません。

Storyboard が重視する点は画面の関係性と遷移関係、 Xib を利用して、共通コンポーネントを作って、再利用 (reuse) できるのはすごく良いだと思います。

この新規アプリはシリーズアプリなので、共通のデザインで実装していきました。アプリ内はいくつかの dialog があって、ほぼ header と footer が付いています。こんな利用シーンで、Xib を利用していいんじゃないですかって思いましたので、結局 dialog を ViewController にした、Storyboard で Present Modally を利用して、遷移関係ははっきり見えます。header と footer の部分は Xib を作って、独立な View として、必要に応じて、画面にロードできます。その上、@IBInspectable@IBDesignable を定義すれば、結構使いやすくなります。メリットは画面デザインと遷移関係両方はっきり見えて、再利用も簡単にできます;デーメリットは Auto Layout の設定を何度もやらないといけませんかな。

心得

Storyboard Reference

「コンフリクトは発生しやすい」ーー Storyboard Reference が誕生した後、こういう話は完全に誤解 (false statement) になりました。

Storyboard Reference は Xcode 7 からサポートされ始めました、部品ライブラリから画面へドラッグできます。既存の Storyboard を分解したいならば、Editor -> Refactor to Storyboard で実現できます。例えば、Container View は二個あって、こんな場合画面の中にある controller の数は三つです。分解して、下のようななります、Container View は別 Storyboard に分かれています:

storyboard_reference.png

それで、チームワークでも、コンフリクトはほぼなくなるかな。もちろん、設計の良い構造を目指して工夫することはいちばん大切なことです。

Loadable Nib

重複コードを減らせるため、型安全のため、Nib のロードをプロトコルにしよう!

protocol Loadable: class {
    static var nibName: String { get }
}

extension Loadable {
    static var nibName: String { return String(describing: Self.self) }
}

UIViewExtension を定義して、ロードされたい View は Loadable プロトコルを採用することが要求されます。ちなみに、Nib は Xib がコンパイルされた後のものです。

extension UIView {
    // Custom Class
    func instantiateFromNib<T: UIView>(_:T.Type) -> T where T: Loadable {
        if let nib = UINib(nibName: T.nibName, bundle: nil).instantiate(withOwner: nil, options: nil).first as? T {
            return nib
        } else {
            fatalError("Nib \(T.nibName) is not exist ?!")
        }
    }
    // File's Owner
    func instantiateFromNibOwner<T: UIView>(_:T.Type) where T: Loadable {
        let bundle = Bundle(for: type(of: self))
        if let nib = UINib(nibName: T.nibName, bundle: bundle).instantiate(withOwner: self, options: nil).first as? UIView {
            nib.frame = self.bounds
            nib.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            self.addSubview(nib)
        } else {
            fatalError("Nib \(T.nibName) is not exist ?!")
        }
    }
}

それで、簡潔なコードで初期化できます:

	let view:ClassName = self.instantiateFromNib(ClassName.self)
	self.instantiateFromNibOwner(ClassName.self)

追記:LoadableNib Library と Demo を Github にアップされました。

ちょっと前、Reusable というライブラリを知りました。Nib の再利用について同じことをやっています、しかも、Cell、Storyboard、ViewController の再利用も実現されました、もっと強いと言えます。

Nib の再利用について、上記方法と Reusable の相違点は:

  1. Reusable に、Nib を初期化する部分は UIViewExtension じゃなくて、Protocol Extension です。
  2. File's Owner として再利用する時,ReusableAuto Layout を使っていて、自分は frame から着手しました。。

@IBDesignable@IBInspectable

@IBDesignable:リアルタイムにビューを描画する。
@IBInspectableRuntime Attributes を定義する。

例:DialogHeaderView を定義、前に @IBDesignable を付して、このクラスの headerTitle 属性を @IBInspectable 付きで定義します:

@IBDesignable class DialogHeaderView: UIView {
    
    @IBInspectable var headerTitle: String = "" {
        didSet {
            navigationBar.topItem?.title = self.headerTitle
        }
    }
    ...
}

ターゲットビューに UIView をおいて、Custome ClassDialogHeaderView に設定,この時 Attribuite Inspector@IBInspectable 付きの属性に値を設置できます:

IB1.png

Runtime Attributes 欄からも設置できますが:

IB2.png

一瞬、ターゲットビューに DialogHeaderView がリアルタイムで表示されます〜

ちょっと残念ですが、リアルタイムビルドの途中に失敗することは少なくないです。念のため、デバッグ方法を覚えておいたほうがいい:Editor -> Debug Selected Views。だいたいすぐエラーを解消できると思います。

型安全

Loadable を除いて、型安全のため、ほかのできることまだあります。

Storyboard は存在するから、Segue の定義はぜったいあリます。identifier は文字列なので、ビューの文字列とコード中の文字列が合っていない場合はたまたまあることで、R.swift の導入をお勧めしたいです。

R.swift は広く使われて型安全の対応をしています、画像 (Image)、フォント (Font)、多言語 (Localization) なども、R.swift から得るところは少なくないです。

13
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?