2016-04-28 2 views
0

У меня есть код в настоящее время в моем проекте IOS, который выглядит следующим образом:Эквивалент для контура сложного условия

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

Я теперь получать предупреждения, что этот стиль для цикла устареет. Везде, где я смотрю на Stack Overflow и в других местах, предлагается использовать шаг для сложных циклов. Тем не менее, шаг не помогает мне здесь, так как конечное условие не является простым сравнением с другим целым числом.

Как это сделать в быстром режиме с помощью встроенного контура?

Примечание. Я мог бы зацикливать CGFloat, но я хочу избежать инкрементной ошибки, повторно добавляя поплавки.

Я мог бы использовать цикл while, но у меня есть несколько из этих циклов в одной и той же функции, и для создания новой новой области для i. Swift, похоже, не похож на произвольные новые области.

Редактировать: в соответствии с ответом @ Sulthan, я создал SequenceType для этого. IMO, что-то, как это должно быть в стрижа, если для петель удаляются:

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

Как я уже сказал, у меня есть многие из этих циклов в одном и том же объеме, поэтому «я» должен быть переоформлен. Насколько я знаю, у Свифта нет каких-либо областей. –

0

Вы можете сделать это с помощью цикла в то время:

var i: Int = 0 

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

Я думаю, что их намерение состоит в том, что for-in используется, когда число раз выполняется, как известно, и while, когда это обусловливается переменных, которые могут быть модифицированным внутри цикла.

Вы также можете использовать оператор условного разрыва в пределах for-in, но while кажется чище.

1

Всегда есть рекурсия!Избегает во время циклов, позволяя вам справляться с изменяющимися ограничениями. И это функционально! ;-)

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? –

+0

Вы можете использовать что-то вроде CGFloat.max, если хотите, но это должен быть ваш bounds.width. Я изменил решение, чтобы быть ближе к вашему примеру (не мог ввести некоторые из этих значений на игровой площадке Swift, которую я использовал, поэтому он не проверен) –

Смежные вопросы