LoginSignup
7
7

More than 5 years have passed since last update.

"UIViewに配置された特定のUI部品を検索する"の改良

Posted at

UIViewに配置された特定のUI部品を検索する では、UI部品のクラスによって検索を行った。
本記事では、自由な検索条件を設定できるよう改良した結果を紹介する。

UILabelのインスタンスを検索するコード

改良前
import UIKit

class FirstViewController: UIViewController {

    var array:[AnyObject]!

    override func viewDidLoad() {
        super.viewDidLoad()        
        array = []

        // FirstView内のUILabelを検索する
        retrieveUIView(UILabel.self, parentView: self.view)

        println("UILabelの数: \(array.count)")
    }

    // parentViewのsubviews以下を検索
    // aClassのインスタンスがあればarrayへ追加
    func retrieveUIView(aClass: AnyClass, parentView: UIView) {
        for childView in parentView.subviews {

            // childViewのクラス名を出力
            // println("クラス: \(childView.dynamicType.description())")

            // childViewがaClassのインスタンスならばarrayに追加
            if (childView as NSObject).dynamicType.isEqual(aClass) {
                array.append(childView)
            }

            // 子のビューについて再帰
            retrieveUIView(aClass, parentView: childView as UIView)
        }
    }
}

新しいretrieveUIView関数

func retrieveUIView(parentView: UIView, var arrayAppendTo array: [UIView]?, viewShouldAppend: (UIView) -> Bool) -> [UIView]
  • parentsViewのsubviews以下を再帰的に検索する
  • 指定された検索条件に合致した要素をarrayに追加し、このarrayを返す。
  • 検索条件はviewShouldAppend関数で決定する。引数のviewを配列に追加すべきであればtrue、そうでなければfalseを返すものとする。

引数

parentView: UIView
検索対象のUI部品
arrayAppendTo array: [UIView]
検索条件にマッチしたUI部品を格納する配列
viewShouldAppend: (UIView) -> Bool
検索条件(配列に格納するかどうか)を決定する関数。

戻り値

検索条件に合致したUIViewの配列

改良後
import UIKit

class FirstViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // 引数のUIViewがUILabelであるか否かを返す
        func isUILabel(view: UIView) -> Bool { return view.dynamicType.isKindOfClass(UILabel) }
        // retrieveUIView関数の呼び出し例1
        let labels = retrieveUIView(self.view, arrayAppendTo: nil, viewShouldAppend: isUILabel)
        println("UILabelの数: \(labels.count)")

        // retrieveUIView関数の呼び出し例2
        let views = retrieveUIView(self.view, arrayAppendTo: labels) { view in
            // UILabel以外はtrueを返す
            !view.dynamicType.isKindOfClass(UILabel)
        }

        println("子ビューの数: \(views.count)")
    }

    // retrieveUIView関数の定義
    func retrieveUIView(parentView: UIView, var arrayAppendTo array: [UIView]?, viewShouldAppend: (UIView) -> Bool) -> [UIView] {

        if (array == nil) { array = [] }

        for childView in parentView.subviews {
            viewShouldAppend(childView as UIView) ? array!.append(childView as UIView) : ()
            array = retrieveUIView(childView as UIView, arrayAppendTo: array, viewShouldAppend)
        }

        return array!
    }   
}

retrieveUIView関数の呼び出し

呼び出し例2では、Trailing Closureというクロージャの記述法により関数の宣言を省いている。

呼び出し例2
let views = retrieveUIView(self.view, arrayAppendTo: labels) { view in
    // UILabel以外はtrueを返す
    !view.dynamicType.isKindObClass(UILabel)
}

Trailing Closure

関数が最後の引数に関数またはクロージャを取る場合、クロージャを引数リストの後に記述することが出来る。

in の前に引数リストと戻り値の型を記述する。
関数でいえばviewが仮引数にあたり、 in 以降は関数の本文となる。
型推論により引数の型、戻り値の型は省略できる。戻り値がVoid型の場合は-> "戻り値の型" も省略できる。
また、本文が1文のみの場合は return も省略できる。

検索条件を設定するクロージャのサンプル

全ての子ビュー

{ _ in true }

クロージャの引数を利用しない場合、仮引数は_(アンダースコア)とすることが出来る。

あるクラスのインスタンスであるか

UIViewはNSObjectのサブクラスであるから、NSObjectプロトコルを実装する。故にisMemberOfClass関数が利用出来る。

{ view in view.isMemberOfClass(目的のクラス名) }

複数のクラスを対象にするならばswitch文を使うべきか。

{ view in
  switch view {
  case let x where x.isMemberOfClass(目的のクラス名1):
      return true
  case let x where x.isMemberOfClass(目的のクラス名2):
      return true
  default:
      return false
  }
}

あるクラス、またはそのサブクラスのインスタンスであるか

isMemberOfClass関数と同様に、NSObjectプロトコルのisKindOfClass関数が利用できる。

{ view in view.isKindOfClass(目的のクラス名) }

幅が100より大きいビュー

{ view in view.frame.width >= 100 }

ビューの中心が画面の上半分にあるビュー

{ view in
    let centerY = UIScreen.mainScreen().bounds.height / 2
    return view.center.y > centerY
}
7
7
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
7
7