2016-04-28 84 views
0

我的代碼目前在我的iOS項目,看起來像這樣:等效for循環的複雜條件

for var i = 0; CGFloat(i) * gridSpacing.width * scale < bounds.width; ++i 

我現在收到警告說,這種風格for循環將被棄用。無論我在Stack Overflow和其他地方看到什麼,都建議對複雜for循環使用stride。然而,這裏的步幅並沒有幫助我,因爲最終條件不是與另一個整數的簡單比較。

如何在swift中使用for-in循環執行此操作?

請注意,我可以循環一個CGFloat,但我想通過反覆添加浮動來避免增量錯誤。

我也可以使用while循環,但是我在同一個函數中有幾個這樣的循環,併爲i創建了一個很好的新範圍。 Swift似乎不喜歡任意新的範圍。

編輯:基於@ Sulthan的回答,我創建了一個SequenceType來完成此操作。 IMO,這樣的事情應該是SWIFT如果毛圈被刪除:

struct forgenerator : GeneratorType 
{ 
    typealias Element = Int 
    typealias Condition = (Element) -> Bool 
    var idx : Element 
    var condition : Condition 
    var increment: Element 

    mutating func next() -> Element? { 
     if condition(idx) 
     { 
      let result = idx 
      idx += increment 
      return result 
     } 

     return nil 
    } 
} 

struct forsequence : SequenceType 
{ 
    typealias Generator = forgenerator 
    var startPoint : Generator.Element 
    var condition : Generator.Condition 
    var increment : Generator.Element 

    func generate() -> Generator { 
     return forgenerator(idx: startPoint, condition: condition, increment: increment) 
    } 
} 


func forgen(start: Int, condition: (Int) -> Bool, increment: Int) -> forsequence 
{ 
    return forsequence(startPoint: start, condition: condition, increment: increment) 
} 

func forgen(start: Int, condition: (Int) -> Bool) -> forsequence 
{ 
    return forgen(start, condition: condition, increment: 1) 
} 

用法:

for i in forgen(0, condition: { CGFloat($0) * self.gridSpacing.width * self.scale < self.bounds.width}) 

注意,不得不在這裏使用自無處不因爲所有這些增值經銷商是一個類的成員。

回答

0

讓我們去步驟:

let itemWidth = gridSpacing.width * scale 
for var i = 0; CGFloat(i) < bounds.width/itemWidth; ++i { 
} 

現在,您可以直接

let itemWidth = gridSpacing.width * scale 
let numItems = Int(floor(Double(bounds.width/itemWidth))) 

for var i = 0; i < numItems; i++ { 
} 

for i in 0..<numItems { 
} 

另一種選擇是使用while循環:

(我已經使用了你想避免的解決方案,但是我覺得它還是更好,並且錯誤不太可能比scale引入的錯誤更重要)。

let itemWidth = gridSpacing.width * scale 
var x = 0 
var index = 0 

while (x < bounds.width) { 
    // do something 

    index += 1 
    x += itemWidth 
} 

此外,您可以隨時提取迭代到一個函數:

func strideOverFloats(start: Int, addition: Int, condition: (CGFloat) -> Bool, _ closure: (Int) ->()) { 
    var i = start 

    while (condition(CGFloat(i))) { 
     closure(i)   
     i += addition 
    } 
} 

let width: CGFloat = 200 
let gridSize: CGFloat = 10 
let scale: CGFloat = 2 

strideOverFloats(0, addition: 1, condition: { $0 * gridSize * scale < width}) { 
    print($0) 
} 
+0

這可能是最接近的答案,但我不愛背到結束條件。原始條件要更直接明白。是否有一個更高級別的構造可以迭代一個值直到滿足任意的結束條件? –

+0

@StevenSchveighoffer這正是'while'循環所做的。您也可以將該功能提取到一個函數中,該函數將爲每次迭代執行閉包。或者,如果您想要更抽象的解決方案,請創建您自己的Stridable。 – Sulthan

+0

對,我可以切換到一個while循環,但是變量聲明必須在循環範圍之外(for的一個方便的特性,考慮swift不允許任意範圍)。我正在尋找的是類似於步幅的東西,但是它允許任意的結束條件而不是終點。 –

0

將其更改爲一個while循環?

var i: CGFloat = 0 
while ((i * gridSpacing.width * scale) < bounds.width) { 
    // ... 
    i += 1; 
} 
+0

正如我所說,我有許多這些循環在同一範圍內,所以'我'將不得不重新宣佈。就我所知,Swift沒有任意的範圍。 –

0

你可以用while循環實現這一點:

var i: Int = 0 

while CGFloat(i) * a * b < bounds.width { 
    // Your code 
    i += 1 // ++ is also deprecated 
} 

我認爲他們的意圖是,在正在執行的次數被稱爲for-in使用和while當它是有條件的變量,可以在循環內進行修改。

您也可以在for-in內使用條件break語句,但while看起來更清晰。

1

總有遞歸!避免while循環,同時仍然允許您處理不斷變化的約束。它功能強大! ;-)

func recursion(currentIndex: Int) { 
    guard CGFloat(currentIndex) * gridSpacing.width * scale < bounds.width else { 
     return 
    } 
    // do what you need to 
    recursion(currentIndex + 1) 
} 
0

我也建議更快捷的風格之一:

for index in 0..<gridSpacing.width * scale { 
    // Your code here 
} 
0

我剛剛發現的,在循環中有一個where條款!

使用的例子:

var end: CGFloat = bounds.width 

for i in 0..<(Int(end+1)) where CGFloat(i) * gridSpacing.width * scale < CGFloat(end) { 
    print(i) 
} 
+0

如何定義結束?你能說無限嗎?編輯:我想我可以說Int.max。但我真的不認爲這是我想要的。即使它只執行主體2x,它是否不會循環遍歷所有可能的Ints? –

+0

如果您願意,您可以使用類似CGFloat.max的內容,但這應該是您的bounds.width。 我修改瞭解決方案以接近您的示例(無法在我使用的Swift操場中輸入一些值,所以未驗證) –