我希望UIView
有一个属性,它返回层次结构中视图的所有祖先的序列。这对于找到与特定类型匹配的最近的目的非常有用:
let tableView = cell.ancestors.first(where: { $0 is UITableView })
实施ancestors
财产的好方法是什么?
使用来自Swift标准库的sequence(first:next:)
函数,也可以实现更短的解决方案:
extension UIView {
var ancestors: AnySequence<UIView> {
return AnySequence<UIView>(
sequence(first: self, next: { $0.superview }).dropFirst())
}
}
您可以实现符合Sequence
的类型,并添加在扩展中返回它的属性。 Sequence
通常需要一个makeIterator()
方法,它返回一个符合IteratorProtocol
的类型,但在这种情况下,我们可以使序列充当它自己的迭代器并为两者使用一种类型,这使事情变得非常简单:
斯威夫特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,以便能够执行第一个(where :)比较,如此,
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
}
}
}
由于AnyIterator本身符合Sequence,因此您在上面显示的语句应该可以正常工作。
let tableView = cell.ancestors.first(where: { $0 is UITableView })
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