Here is a possible generic solution which allows to
traverse any "nested sequence". It is not restricted to UIView
and subviews
, but takes a parameter which maps each sequence element to its immediate children.
It also separates the task of traversing the sequence from the
action on the elements (like setting a background color), by returning a Generator
which
can be used with existing methods like forEach()
.
(This is inspired by some answers to Implementing recursive generator for simple tree structure in Swift.)
extension SequenceType {
public func generate<S : SequenceType where S.Generator.Element == Generator.Element>
(children children: Generator.Element -> S) -> AnyGenerator<Generator.Element> {
var selfGenerator = self.generate()
var childGenerator : AnyGenerator<Generator.Element>?
return anyGenerator {
// Enumerate all children of the current element:
if childGenerator != nil {
if let next = childGenerator!.next() {
return next
}
}
// Get next element of self, and prepare subGenerator to enumerate its children:
if let next = selfGenerator.next() {
childGenerator = children(next).generate(children: children)
return next
}
return nil
}
}
}
As an example, if view
is a UIView
then
view.subviews.generate(children: { $0.subviews })
returns a (lazy) generator of all (nested) subviews. By calling forEach()
on this generator, we can modify each subview:
view.subviews.generate(children: { $0.subviews }).forEach {
$0.backgroundColor = UIColor.clearColor()
}
But it could also be used to get an array with all nested subviews:
let allViews = Array(view.subviews.generate(children: { $0.subviews }))