Ios 我如何创建一个序列来迭代从UIView到视图层次到根的所有祖先(超级视图)?

Ios 我如何创建一个序列来迭代从UIView到视图层次到根的所有祖先(超级视图)?,ios,swift,cocoa-touch,uikit,Ios,Swift,Cocoa Touch,Uikit,我希望UIView有一个属性,返回层次结构上视图所有祖先的序列。这对于查找与特定类型匹配的最接近的类型非常有用: let tableView = cell.ancestors.first(where: { $0 is UITableView }) 实现该祖先属性的好方法是什么?您可以实现符合的类型,并在扩展中添加返回该类型的属性。Sequence通常需要一个makeIterator()方法,该方法返回符合的类型,但在这种情况下,我们可以使序列充当自己的迭代器,并对两者使用一种类型,这使得事情非

我希望
UIView
有一个属性,返回层次结构上视图所有祖先的序列。这对于查找与特定类型匹配的最接近的类型非常有用:

let tableView = cell.ancestors.first(where: { $0 is UITableView })

实现该
祖先属性的好方法是什么?

您可以实现符合的类型,并在扩展中添加返回该类型的属性。
Sequence
通常需要一个
makeIterator()
方法,该方法返回符合的类型,但在这种情况下,我们可以使序列充当自己的迭代器,并对两者使用一种类型,这使得事情非常简单:

Swift 3:

struct AncestorSequenceIterator: Sequence, IteratorProtocol {
    var current: UIView
    mutating func next() -> UIView? {
        guard let next = current.superview else { return nil }
        current = next
        return next
    }
}

extension UIView {
    var ancestors: AncestorSequenceIterator {
        return AncestorSequenceIterator(current: self)
    }
}

您可以创建扩展并返回IteratorProtocol,以便能够首先(其中:)进行如下比较

extension UIView {

    var ancestors: AnyIterator<UIView> {
        var current: UIView = self

        return AnyIterator<UIView> {
            guard let parent = current.superview else {
                return nil
            }
            current = parent
            return parent

        }
    }
}
使用Swift标准库中的
序列(first:next:)
功能,还可以使用更短的解决方案:

扩展UIView{ 变量:AnySequence{ 返回任意序列( 序列(第一个:self,下一个:{$0.superview}).dropFirst() } }
Paulo Mattos的实现很好,但对于您的特定用途,您可能需要以下内容:

extension UIView {
    func nearestAncestor<T: UIView>(ofType type: T.Type) -> T? {
        if let me = self as? T { return me }
        return superview?.nearestAncestor(ofType: type)
    }
}
guard let tableView = cell.nearestAncestor(ofType: UITableView.self) else { return }
// tableView at this point is type UITableView

如果
祖先
属性的唯一用途是查找特定类型的父级,则您的解决方案效率低下。您构建了整个祖先列表,但实际上只迭代了前几个(通常)来查找匹配的祖先。为什么要先遍历整个superview列表,然后返回,只迭代前几个列表以找到匹配项?为什么不消除不必要的第一步,只做更短(通常)的第二步呢?可以通过对UIView的简单扩展来实现。您的
祖先
属性可能有其用途,但此用途不是其中之一。@rmaddy这并不是构建一个完整的祖先列表–它只是创建一个迭代器,可以直接在视图层次结构上进行迭代。使用
first(其中:)
将在找到满足谓词的第一个匹配项时短路。如果你想建立一个祖先列表,你必须说类似于
Array(someView.祖先)
@Hamish哦,很好。这否定了我的全部评论。没关系,走吧。这里没什么可看的。:)谢谢。这是一个很好的解决特定问题的方法,但在这种情况下,我想看看是否可以用更通用、更实用的方法来解决:)
guard let tableView = cell.nearestAncestor(ofType: UITableView.self) else { return }
// tableView at this point is type UITableView