Swift:递归遍历所有子视图以查找特定类并附加到数组

时间:2015-08-30 21:29:49

标签: arrays swift recursion uiview

有一段时间试图解决这个问题。我在这里问了一个类似的问题:Swift: Get all subviews of a specific type and add to an array

虽然这有效,但我意识到有很多子视图和子视图,因此我需要一个从主UIView开始的函数,循环遍历所有子视图(及其子视图,直到没有任何左视图并将其添加到一个自定义按钮类的数组中,我将其命名为CheckCircle。

基本上我想最终得到一个CheckCircles数组,它们构成了以编程方式添加到该视图的所有CheckCircles。

有什么想法吗?这是我一直在做的事情。它似乎没有将任何Checkcircles附加到数组中:

    func getSubviewsOfView(v:UIView) -> [CheckCircle] {
        var circleArray = [CheckCircle]()
        // Get the subviews of the view

        var subviews = v.subviews

        if subviews.count == 0 {
            return circleArray
        }

        for subview : AnyObject in subviews{
  if let viewToAppend = subview as? CheckCircle {
        circleArray.append(viewToAppend as CheckCircle)
      }
            getSubviewsOfView(subview as! UIView)
        }
        return circleArray
    }

6 个答案:

答案 0 :(得分:23)

你的主要问题是,当你在函数中递归getSubviewsOfView(subview as! UIView)时,你不会对结果做任何事情。

您还可以删除count == 0检查,因为在这种情况下,只会跳过for…in循环。你还有一堆不必要的演员

假设您希望获得一系列CheckCircle个实例,我认为您的代码适应性应该有效:

func getSubviewsOfView(v:UIView) -> [CheckCircle] {
    var circleArray = [CheckCircle]()

    for subview in v.subviews as! [UIView] {
        circleArray += getSubviewsOfView(subview)

        if subview is CheckCircle {
            circleArray.append(subview as! CheckCircle)
        }
    }

    return circleArray
}

答案 1 :(得分:18)

  

基于 Aaron Brager ullstrm 答案

详细

  • Xcode 9.1,Swift 4,
  • Xcode 10.2(10E125),Swift 5

解决方案

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

    func getAllSubviews<T: UIView>() -> [T] {
        return UIView.getAllSubviews(from: self) as [T]
    }
}

用法

let allLabels = simpleView.getAllSubviews() as [UILabel]

其他信息

另外,我建议使用弱引用。 Array with weak references to objects

答案 2 :(得分:14)

我使用swift 3和泛型的方法!

private func getSubviewsOf<T: UIView>(view: UIView) -> [T] {
    var subviews = [T]()

    for subview in view.subviews {
        subviews += getSubviewsOf(view: subview) as [T]

        if let subview = subview as? T {
            subviews.append(subview)
        }
    }

    return subviews
}

要获取视图层次结构中的所有UILabel,只需执行以下操作:

let allLabels: [UILabel] = getSubviewsOf(view: theView)

答案 3 :(得分:4)

您可以通过扩展UIView并定义以下功能来简单地实现它。

Swift4代码

extension UIView {
    func findViews<T: UIView>(subclassOf: T.Type) -> [T] {
        return recursiveSubviews.compactMap { $0 as? T }
    }

    var recursiveSubviews: [UIView] {
        return subviews + subviews.flatMap { $0.recursiveSubviews }
    }
}

用法

findViews(subclassOf: UILabel.self)
findViews(subclassOf: CheckCircle.self)

答案 4 :(得分:0)

  

基于 Vasily Bodnarchuk Aaron Brager ullstrm 的答案。

为什么还要另一个?

我个人不喜欢遍历as [XXX]let specific: [Type],而是将类型传递给函数调用,例如

let scrollViews = view.getNestedSubviews(ofType: UIScrollView.self)
print(scrollViews) // outputs: [UIScrollView]

我也将All重命名为Nested,因为它可以更好地将函数的递归性质传达给API调用者。

详细信息

Swift 4.x,Xcode 9.1 +

解决方案

extension UIView {

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

    func getNestedSubviews<T: UIView>() -> [T] {
        return UIView.getNestedSubviews(view: self) as [T]
    }
}

用法

let scrollViews = view.getNestedSubviews(ofType: UIScrollView.self)
print(scrollViews) // outputs: [UIScrollView]

答案 5 :(得分:-1)

UITextField不再位于子视图的顶层,因此我使用此方法:

@implementation UISearchBar (changeFont)

- (void)setFont:(UIFont *)font {
    for (UIView *v in [self subviews]) {
        if ([v isKindOfClass:[UITextField class]]) {
            UITextField *tf = (UITextField *)v;
            tf.font = font;
            UILabel *l = (UILabel *)[tf valueForKey:@"placeholderLabel"];
            l.font = font;
            break;
        } else if (v.subviews.count) {
            for (UIView *v1 in v.subviews) {
                if ([v1 isKindOfClass:[UITextField class]]) {
                    UITextField *tf = (UITextField *)v1;
                    tf.font = font;
                    UILabel *l = (UILabel *)[tf valueForKey:@"placeholderLabel"];
                    l.font = font;
                    break;
                } else if (v1.subviews.count) {
                    for (UIView *v2 in v1.subviews) {
                        if ([v2 isKindOfClass:[UITextField class]]) {
                            UITextField *tf = (UITextField *)v2;
                            tf.font = font;
                            UILabel *l = (UILabel *)[tf valueForKey:@"placeholderLabel"];
                            l.font = font;
                            break;
                        }
                    }
                }
            }
        }
    }
}

有点long绕,但应该说明将来文本字段会更深入