2016-03-23 1 views
3

Sieht aus wie Apple C-Schleifen nicht mag, aber bietet keine gute Annäherung darüber (oder ich konnte es nicht finden). Ich habe solche Schleife, um von einer Ansicht zum root in der UI-Hierarchie zu gehen:Swift 3: Wie schreibe ich das für (;;) Schleife

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

Wie schreibe ich dies in Swift 3 Weise?

+1

** nicht von Apple Es ist wirklich ** wer mag C-Schleifen nicht, aber [Erica Sadun] (https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md), Andy Matuschak (Khan-Akademie), Keith Smiley (Lyft) und andere in der Mailing-Liste. Chris Lattner (Apple) steht ihnen offen gegenüber. Schließlich hat der Ausschuss zugestimmt, ihn zu streichen. – adib

+0

Bitte fügen Sie die Lösung nicht als "Update" zu der Frage hinzu. Wenn Sie Ihre eigene Lösung teilen möchten, können Sie eine Antwort posten. – FelixSFD

+1

@FelixSFD danke für den Rat, extrahiert, dass zu beantworten – brigadir

Antwort

2

Dies wäre ein Weg, es in Swift zu tun 3:

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

Wenn Sie den Loop Progression Sachen neben while und nicht am Ende des Blocks gruppieren möchten, können Sie defer wie folgt verwenden :

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

Wenn Sie den Bereich von parentView beschränken möchten, können Sie alles in einem do Block kapseln:

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

Aber es ist ziemlich ausführliche, so dass Sie eine neue generische Funktion für ähnliche Schleifen, wie diese definieren könnte:

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 
} 

Und eine letzte, die auf GeneratorType und SequenceType setzt mit der for-in-Schleife Syntax zu ermöglichen :

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 
} 
+0

Optional kann sicher innerhalb der While-Schleife ausgepackt werden – pkacprzak

+1

Ich aktualisierte meine Antwort zu einem impliziten optionalen anstelle eines expliziten verwenden. – Valentin

+0

Dies wird abstürzen, wenn parentView schließlich null wird. Sie können es so lassen, wie es vorher war, oder das optionale in der while-Schleife entfernen – pkacprzak

0

Zum Beispiel

for view in views where view.superview != nil { 
} 
+0

Was ist 'Ansichten'? – brigadir

1

Corr ect aber zu späte Antwort: Es gibt eingebaute Funktionen in Swift 3, die die Lösung bieten:

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> 

Wir sie auf diese Weise verwenden können:

sequence(first: view, next: { 
    // do something with $0... 
    return $0.superview 
}) 
+0

Sie brauchen das for in nicht, wenn Sie es nicht verwenden. Verwenden Sie nur die Sequenzfunktion. – Binarian

+1

wahr! Danke für die Korrektur – brigadir