Swift - 避免嵌套forEach闭包?

时间:2016-05-25 18:15:57

标签: ios arrays swift functional-programming

假设我有一系列我想在每个UITouch上运行的闭包。 这是我使用的代码:

touches.filter { touch in
    return touch.phase == .Ended && touch.tapCount == 1
}.forEach { touch in
    actionsOnTap.forEach { action in
        action(touch)
    }
}

这让我觉得有嵌套的forEach语句,我想有一些干净的方法可以完全适用于那种情况,但我想不到它。谁能给我一个提示?

4 个答案:

答案 0 :(得分:8)

就个人而言,我喜欢嵌套。我会写:

for touch in touches {
    if touch.phase == .Ended {
        if touch.tapCount == 1 {
            actionsOnTap.forEach {$0(touch)}
        }
    }
}

对我来说,这很干净(最重要的是)清晰。

答案 1 :(得分:6)

为了提高效率和简洁性,您绝对应该从逻辑中消除filter并在第一个循环中使用guard。我同意@Rob's@matt's建议使用传统的for循环代替forEach - 至少对于第一个循环。

虽然(可能更干净)替代方案是通过使用for子句直接将触摸条件逻辑集成到where循环中,以及可能将forEach折叠成一个单行(无论哪个更易读)。

我会这样写:

for touch in touches where touch.phase == .Ended && touch.tapCount == 1 {
    actionsOnTap.forEach{$0(touch)}
}

答案 2 :(得分:4)

这是forEach不是for-in的通用(甚至是适当的常见)替代原因的一个很好的例子。这段代码变得更短(140个字符与186个字符)并且使用传统的for循环更清晰:

for touch in touches where touch.phase == .Ended && touch.tapCount == 1 {    
    for action in actionsOnTap {
        action(touch)
    }
}

它也不像filter那样创建额外的数组副本。这不是使用filter的一般原因。 filter是一个非常强大的工具,应该经常使用,但在这种情况下,使用for会更加清晰

已编辑使用@ originaluser2的where而不是guard的建议。这可能是更好的Swift。

答案 3 :(得分:1)

由于您有两种异构数组类型。避免filter做的额外迭代的另一个解决方案就是过滤你要检查的触摸。

touches.forEach{
  guard $0.phase == .Ended && $0.tapCount == 1 else { return }

  actions.forEach{ action in
     action($0)
  }
}