Swift: Recursively cycle through all subviews to find a specific class and append to an array

Based on Aaron Brager and ullstrm answers

Details

  • Xcode 9.1, Swift 4,
  • Xcode Version 10.3 (10G8), Swift 5

Solution

extension UIView {

    class func getAllSubviews<T: UIView>(from parenView: UIView) -> [T] {
        return parenView.subviews.flatMap { subView -> [T] in
            var result = getAllSubviews(from: subView) as [T]
            if let view = subView as? T { result.append(view) }
            return result
        }
    }

    class func getAllSubviews(from parenView: UIView, types: [UIView.Type]) -> [UIView] {
        return parenView.subviews.flatMap { subView -> [UIView] in
            var result = getAllSubviews(from: subView) as [UIView]
            for type in types {
                if subView.classForCoder == type {
                    result.append(subView)
                    return result
                }
            }
            return result
        }
    }

    func getAllSubviews<T: UIView>() -> [T] { return UIView.getAllSubviews(from: self) as [T] }
    func get<T: UIView>(all type: T.Type) -> [T] { return UIView.getAllSubviews(from: self) as [T] }
    func get(all types: [UIView.Type]) -> [UIView] { return UIView.getAllSubviews(from: self, types: types) }
}

Usage sample

var allViews = UIView.getAllSubviews(from: simpleView)
func printResult(with text: String) {
    print("\n==============================================")
    print("\(text):\n\(allViews.map { $0.classForCoder } )")
}
printResult(with: "UIView.getAllSubviews(from: simpleView)")

allViews = UIView.getAllSubviews(from: simpleView) as [UILabel]
printResult(with: "UIView.getAllSubviews(from: simpleView) as [UILabel]")

allViews = UIView.getAllSubviews(from: simpleView, types: [UIStackView.self, UILabel.self])
printResult(with: "UIView.getAllSubviews(from: simpleView, types: [UIStackView.self, UILabel.self])")

allViews = simpleView.getAllSubviews()
printResult(with: "simpleView.getAllSubviews()")

allViews = simpleView.getAllSubviews() as [UILabel]
printResult(with: "simpleView.getAllSubviews() as [UILabel]")

allViews = simpleView.get(all: UILabel.self)
printResult(with: "simpleView.get(all: UILabel.self)")

allViews = simpleView.get(all: [UIStackView.self, UILabel.self])
printResult(with: "simpleView.get(all: [UIStackView.self, UILabel.self])")

Output of the sample

==============================================
UIView.getAllSubviews(from: simpleView):
[UILabel, UIButton, UILabel, UILabel, UILabel, UIStackView]

==============================================
UIView.getAllSubviews(from: simpleView) as [UILabel]:
[UILabel, UILabel, UILabel, UILabel]

==============================================
UIView.getAllSubviews(from: simpleView, types: [UIStackView.self, UILabel.self]):
[UILabel, UILabel, UILabel, UILabel, UIStackView]

==============================================
simpleView.getAllSubviews():
[UILabel, UIButton, UILabel, UILabel, UILabel, UIStackView]

==============================================
simpleView.getAllSubviews() as [UILabel]:
[UILabel, UILabel, UILabel, UILabel]

==============================================
simpleView.get(all: UILabel.self):
[UILabel, UILabel, UILabel, UILabel]

==============================================
simpleView.get(all: [UIStackView.self, UILabel.self]):
[UILabel, UILabel, UILabel, UILabel, UIStackView]

Storyboard of the sample

enter image description here

Other info

Also, I suggest to work with weak references. Array with weak references to objects

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)