追加記事
コメントで教えてもらった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に限りませんが、他のシーンでも使える場合はあるかもしれません。