3

看起来 Apple 不喜欢 C 循环,但没有提供好的方法(或者我找不到它)。我有这样的循环从某个视图到 UI 层次结构中的根:

for var parentView = view; parentView != nil; parentView = parentView.parent {
    ...
}

如何以 Swift 3 的方式写这个?

4

3 回答 3

2

This would be a way to do it in Swift 3:

var parentView: View! = view
while parentView != nil {
    // Do stuff
    parentView = parentView.parent
}

If you want to group the loop progression stuff next to while and not at the end of block, you may use defer, like this:

var parentView: View! = view
while parentView != nil {
    defer { parentView = parentView.parent }        
    // Do stuff
}

If you want to limit the scope of parentView, you can encapsulate everything in a do block:

do {
    var parentView: View! = view
    while parentView != nil {
        defer { parentView = parentView.parent }        
        // Do stuff
    }
}

But it's quite verbose so you could define a new generic function for similar loops, like this:

func kindaCStyleLoop<T>(first: T, obtainNext: T -> T?, action: T -> ()) {
    var current: T! = first
    repeat {
        action(current)
        current = obtainNext(current)
    } while current != nil
}

kindaCStyleLoop(view, obtainNext: { $0.parent }) {
    // Do stuff with $0
}

And a last one that relies on GeneratorType and SequenceType to enable using the for-in-loop syntax:

struct CStyleGenerator<T> : GeneratorType, SequenceType {
    let getNext: T -> T?
    var current: T!

    init(first: T, getNext: T -> T?) {
        self.getNext = getNext
        self.current = first
    }

    mutating func next() -> T? {
        defer {
            if current != nil {
                current = getNext(current)
            }
        }
        return current
    }
}

for parentView in CStyleGenerator(first: view, getNext: { $0.parent }) {
    // Do stuff with parentView
}
于 2016-03-23T12:43:49.223 回答
1

正确但为时已晚的答案:Swift 3 中有提供解决方案的内置函数:

public func sequence<T>(first: T, next: (T) -> T?) -> UnfoldSequence<T, (T?, Bool)>
public func sequence<T, State>(state: State, next: (inout State) -> T?) -> UnfoldSequence<T, State>

我们可以这样使用它们:

sequence(first: view, next: {
    // do something with $0...
    return $0.superview
})
于 2016-11-28T09:36:11.187 回答
0

例如

for view in views where view.superview != nil {
}
于 2016-03-25T10:53:29.853 回答