循环复杂条件的等价

时间:2016-04-28 19:27:06

标签: swift

我目前在iOS项目中的代码如下所示:

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

我现在收到警告,这个样式for循环将被弃用。我在Stack Overflow和其他地方看到的每个地方都建议使用stride进行复杂的for循环。但是,stride对我没有帮助,因为结束条件不是与另一个整数的简单比较。

如何使用for-in循环快速执行此操作?

注意,我可以循环一个CGFloat,但我想通过重复添加浮点数来避免增量错误。

我也可以使用while循环,但是我在同一个函数中有几个这样的循环,并且为i创建了一个很好的新范围。斯威夫特似乎不喜欢任意新的范围。

编辑:根据@ Sulthan的回答,我创建了一个SequenceType来执行此操作。 IMO,如果要删除for循环,这样的事情应该很快:

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

注意,不得不在各处使用self,因为所有这些变量都是一个类的成员。

6 个答案:

答案 0 :(得分:1)

总有递归!避免循环,同时仍然允许您处理更改约束。它功能齐全! ; - )

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

答案 1 :(得分: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)
}

答案 2 :(得分:0)

将其更改为while循环?

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

答案 3 :(得分:0)

您可以使用while循环完成此操作:

var i: Int = 0

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

我认为他们的意图是,当执行的次数已知时使用for-in,而while的条件是可以在循环内修改的变量。{/ {} p>

您还可以在for-in中使用条件中断语句,但while似乎更清晰。

答案 4 :(得分:0)

我还建议更快捷的风格:

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

答案 5 :(得分:0)

我刚刚发现for-in循环有一个where子句!!

用法示例:

var end: CGFloat = bounds.width

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