2016-03-23 4 views
3

Похоже, что Apple не любит циклы C, но не обеспечивает хороший подход к ней (или я не мог ее найти). У меня есть такой цикл, чтобы перейти от некоторой точки зрения на корень в иерархии пользовательского интерфейса:Swift 3: как написать это для цикла (;;)

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

Как написать это в Swift 3 образом?

+1

Это действительно ** не Apple, ** который не любит C-петли, но [Эрика Садун] (https://github.com/apple/swift-evolution/blob/master/proposals/0007-remove-c-style-for-loops.md), Энди Матушак (Академия Хана), Кит Смайли (Лейф) и другие в списке рассылки. Крис Лэттнер (Apple) просто открыт для них. Наконец, комитет согласился удалить его. – adib

+0

Пожалуйста, не добавляйте решение в качестве «Обновить» к вопросу. Если вы хотите поделиться своим решением, вы можете отправить ответ. – FelixSFD

+1

@FelixSFD благодарит за консультацию, извлек это, чтобы ответить – brigadir

ответ

2

Это был бы способ сделать это в Swift 3:

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

Если вы хотите сгруппировать рамочные прогрессии вещей рядом с while, а не в конце блока, вы можете использовать defer, как это :

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

Если вы хотите ограничить сферу parentView, вы можете инкапсулировать все в do блоке:

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

Но это довольно громоздким, чтобы вы могли определить новую обобщенную функцию для подобных циклов, например:

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 
} 

И последний тот, который опирается на GeneratorType и SequenceType для того, чтобы, используя синтаксис-в-петле :

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

Необязательно может быть безопасно развернуто внутри цикла while – pkacprzak

+1

Я обновил свой ответ, чтобы использовать неявный дополнительный, а не явный. – Valentin

+0

Это приведет к сбою, когда parentView станет нулевым. Вы можете оставить его так, как было раньше, или развернуть необязательный внутри цикла while. – pkacprzak

0

например

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

Что такое 'views'? – brigadir

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

Вам не нужно использовать for, если вы его не используете. Используйте только функцию последовательности. – Binarian

+1

true! Спасибо за исправление – brigadir