2017-07-26 43 views
10

作为记录在两个ArrayDictionaryforEach(_:)实例方法:何时使用forEach(_ :)而不是in?

呼叫以相同的顺序 在序列每个元素在给定的封闭件的for-in循环。

然而,改编自Sequence Overview

序列是,你可以在 时间通过一个步骤值的列表。 用于遍历序列 的元素的最常用方式是使用for-in循环

言下之意是由forEach(_:)for in迭代序列:

let closedRange = 1...3 

for element in closedRange { print(element) } // 1 2 3 

closedRange.forEach { print($0) } // 1 2 3 

或(阵列):

let array = [1, 2, 3] 

for element in array { print(element) } // 1 2 3 

array.forEach { print($0) } // 1 2 3 

将给出相同的输出。

为什么forEach(_:)竟然存在?即使用它代替for in循环有什么好处?从性能角度看他们会是一样的吗?

作为一个假设,它可能是一个语法糖,特别是在使用函数式编程时。

+0

从性能的角度来看'forEach'是**米ù] C H **比为'loop'慢。但是它也可以方便地用作Objective-C的'makeObjectsPerformSelector:' – vadian

+2

@vadian - 在调试版本中它慢得多。在发布版本中不一定是真的(显然,取决于代码中的其他内容)。例如,我只是通过在发布版本中有数百万对象的数组进行迭代测试,并且性能差异是难以区分的。 – Rob

+0

@Rob感谢您的反馈。事实上,我的“基准测试”是在调试模式下执行的(只是⌘运行该项目) – vadian

回答

15

forEach没有性能优势。实际上,if you look at the source code,forEach功能实际上只是执行for-in。对于发布版本,这个函数的性能开销通过简单地使用for-in本身并不重要,但对于调试版本而言,它会导致可观察的性能影响。

forEach主要优点是实现了,当你在做函数式编程,你可以将它添加到的功能调用链,而无需事先结果保存到一个单独的变量,如果你使用的是for你需要 - in语法。因此,而不是:

let objects = array.map { ... } 
    .filter { ... } 

for object in objects { 
    ... 
} 

您可以改为留内的功能的编程模式:

array.map { ... } 
    .filter { ... } 
    .forEach { ... } 

结果是功能代码,用更少的语法噪音更简洁。

FWIW,为ArrayDictionary的文档,并Sequence都提醒我们通过forEach所引入的限制的,即:

  1. 您不能使用breakcontinue声明退出当前 通话body关闭或跳过后续的呼叫。

  2. body封闭使用return语句只会从 当前呼叫退出到body,而不是从任何外部范围,并不会跳过 后续调用。

+0

感谢@Rob。这是否意味着我们只能通过函数式编程才能使用'forceah'? –

+0

我不会坚持只能将它与函数式编程结合使用。这是一个很好的简洁语法,您可以随时随地使用它。我只是在暗示它最大的用处是与函数式编程结合使用,相比之下,''''in'模式真的变得非常麻烦。 – Rob

+0

@Rob根据你的建议,我发布了一个与此相关的衍生问题。 https://stackoverflow.com/questions/47743259/use-foreach-to-nil-out-values-in-an-array – Adrian

-2

他们都或多或少可以互换的,但有两个重要的区别。

  1. break/continue只在for .. in
  2. return工作,forEach将退出关闭,但不会停止迭代。

这样做的原因是,for .. in是在语言特殊形式(允许突破,并继续按照您的预期工作)。这是你无法用语言本身以同样的方式实现的东西。

但是,forEach不是一种特殊形式,可以通过将其作为函数编写来重新实现。

extension Sequence { 
    func myOwnForEach(_ body: (Self.Element) throws -> Void) rethrows { 
     let it = Self.makeIterator() 
     while let item = it.next() { 
      body(item) 
     } 
    } 
} 
3

我最近遇到一个使用情况下使用forEach是最好有形的方式来for in跑去。假设您想要从图层中删除所有子图层。如下面的说明,如你需要解开的[CALayer]

for layer in self.videoContainerView.layer.sublayers! 

如果子层零,你会得到一个崩溃不能正常工作。这迫使你先检查是否有子层。然而,forEach使得如下面的这个更简单:

self.videoContainerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() } 
相关问题