LoginSignup
7
8

More than 5 years have passed since last update.

Viewの初期化を末尾closureで与えて見やすくするためのextension

Last updated at Posted at 2016-05-28

追加記事

コメントで教えてもらったtapの実装もしたので、好きな方を選んで使ってください。

NSObjectにRuby, Underscoreライクなtapのextension実装
http://qiita.com/gamako/items/c83d4eeacda6c11a77ef

本文

Viewの組み立てをコードで行っていると、変数のスコープや名前付けが煩雑になり、かつ縦横に長くになってきがちです。

次のようなextensionを置いておくと、イニシャライザの呼び出しと、外部からの初期化を末尾closureにまとめた書き方ができるようになりました。
こんなのどうでしょうか。

初期化がコンパクトにまとまるので、いまのところ見やすくなった気がします。

まずこれがextensionです

protocol NoescapeClosureInitialzable : class {
}

extension UIView : NoescapeClosureInitialzable {}

extension NoescapeClosureInitialzable where Self : UIView {
    init(@noescape _ initializer: (view : Self) -> ()) {
        self.init()
        initializer(view: self)
    }
    init(frame: CGRect, @noescape _ initializer: (view : Self) -> ()) {
        self.init(frame: frame)
        initializer(view: self)
    }
}

extension NoescapeClosureInitialzable where Self : UIButton {
    init(type: UIButtonType, @noescape _ initializer: (view : Self) -> ()) {
        self.init(type: type)
        initializer(view: self)
    }
}

使い方の例

その1


// viewDidLoadの中などにて

let contentView = UIView(frame: self.view.bounds) { (v : UIView) -> Void in
    // ここに初期化を書ける
    // UIView(frame: ...)で生成されたインスタンスが引数で与えられるので、これに対して操作を行う
    v.backgroundColor = UIColor.blackColor()
    v.translatesAutoresizingMaskIntoConstraints = false

    // Autolayoutの制約など書くなど

    // 外側のselfへの参照は、selfと書く必要なし
    view.addSubview(v)
}

その2

let _ = UILabel() { // closureの型を省略すると$0で参照できるのでこちらがおすすめ
    $0.backgroundColor = UIColor.blackColor()
    $0.translatesAutoresizingMaskIntoConstraints = false
    $0.text = "ラベル名"

    // Autolayoutの制約など書くなど

    contentView.addSubview($0)
}

その3

// 多少高度な入れ子
// UIStackViewにテキストフィールド2つと、ラベル、ボタンを配置して返す。
let (usernameText, passText, errorLabel, loginButton) = { _ -> (UITextField, UITextField, UILabel, UIButton) in
    let baseView = UIStackView() {
        $0.translatesAutoresizingMaskIntoConstraints = false
        contentView.addArrangedSubview($0)

        $0.axis = .Vertical
        $0.spacing = 8
        $0.distribution = .FillProportionally
    }

    let _ = UILabel() {
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.text = "ユーザー名"
        $0.sizeToFit()
        baseView.addArrangedSubview($0)
    }

    let usernameText = UITextField() {
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.placeholder = "ユーザー名"
        baseView.addArrangedSubview($0)
    }

    let _ = UILabel() {
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.text = "パスワード"
        $0.sizeToFit()
        baseView.addArrangedSubview($0)
    }

    let passText = UITextField() {
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.placeholder = "パスワード"
        baseView.addArrangedSubview($0)
    }

    let errorLabel = UILabel() {
        $0.translatesAutoresizingMaskIntoConstraints = false
        $0.text = "エラーメッセージ"
        $0.sizeToFit()
        baseView.addArrangedSubview($0)
    }

    let button = UIButton(type: .System) {
        $0.setTitle("ログイン", forState: .Normal)
        baseView.addArrangedSubview($0)
    }

    return (usernameText, passText, errorLabel, button)
}()


備考

今回@noescapeを始めて使いましたが、こう使うんですね。
違う型のイニシャライザをもつクラスで使いたい場合は、適宜extensionを追加するとよいでしょう。

また、UIViewに限りませんが、他のシーンでも使える場合はあるかもしれません。

7
8
2

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
7
8