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