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


# 追加記事

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

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

# 本文

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

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

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



まずこれがextensionです

https://gist.github.com/gamako/84ec986f85fd26ceccae1b92c6df2f29

```swift
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)
    }
}

```



## 使い方の例

その１

```swift

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

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

    contentView.addSubview($0)
}
```

その3


```swift
// 多少高度な入れ子
// UIStackViewにテキストフィールド２つと、ラベル、ボタンを配置して返す。
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に限りませんが、他のシーンでも使える場合はあるかもしれません。