Swift 标准库里最容易被滥用的就是 Sequence 的 enumerated() 函数。这个函数会返回一个新的序列,包含了初始序列里的所有元素,以及与元素相对应的编号。

enumerated() 很容易被误解。因为它给每一个元素都提供了一个编号,对于很多问题来说这是一个很简便的方案。然而,这些问题大多数都可以被另一种方式更好的解决,让我们来看一下其中的一些例子吧,要注意理解它们有什么问题,然后如何使用更好的抽象去解决它们。

使用 enumerated() 最关键的问题在于大家都认为它返回的是每一个元素和元素的索引值,但实际上并不是这样的。因为它可以适用于所有序列,而序列是不能保证有索引的,由此可知它返回的并不是索引值。下面的代码里,这个变量的名字是 offset,而不是 index,这是接下来文章里会默认使用的命名方式。offset 总是一个整型,从 0 开始,间隔为 1,跟每一个元素逐一对应。对于 Array,这刚好跟它的索引值完全一致,但除此之外的其他所有类型,都不会有这种巧合发生。让我们来看一个例子:

let array = ["a", "b", "c", "d", "e"]
let arraySlice = array[2..<5]
arraySlice[2] // => "c"
arraySlice.enumerated().first // => (0, "c")
arraySlice[0] // fatalError

我们的变量 arraySlice,毫无疑问是 ArraySlice 类型。然而,它的startIndex 很明显是 2,而不是 0,但当我们调用 enumerated()first 的时候, 它会返回一个元组,包含了一个offset,值为 0,以及它的第一个元素 “c”。

你以为,你会获得与下面等价的代码

zip(array.indices, array)

但实际上你获取到的是这个

zip((0..<array.count), array)

如果你不是在使用 Array 的话,随时可能会产生错误的行为。

而且实际上你获取到的是一个 offset,而不是 index,使用 enumerated() 也会有别的问题。很多时候你也许想用 enumerated(), 但有别的更好的抽象可以使用。让我们来看一些例子。

我见到 enumerated() 最常用的方式是对一个数组执行 enumerated,使用返回的 offset 来获取另一个数组对应的元素。

for (offset, model) in models.enumerated() {
let viewController = viewControllers[offset]
viewController.model = model
}

虽然这段代码可以正常运作,但前提是 modelsviewControllers 都是 Array 类型,使用整型来作为索引值类型,从 0 开始。另一个前提是这两个数组拥有相同的长度。如果models 的数组长度比 viewControllers 短的话,就会崩溃。我们还多了一个没有实际意义的多余的变量 offset。一个简洁的 Swift 实现方式应该是:

for (model, viewController) in zip(models, viewControllers) {
viewController.model = model
}

这段代码更加简洁,而且适用于所有 Sequence 类型,而且可以安全地处理不等长的数组。

让我们看看另一个例子,这段代码给第一个 imageView 和它的容器以及每个 imageView 之间添加了一段 autolayout 的约束

for (offset, imageView) in imageViews.enumerated() {
if offset == 0 {
imageView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true
} else {
let imageToAnchor = imageView[offset - 1]
imageView.leadingAnchor.constraint(equalTo: imageToAnchor.trailingAnchor).isActive = true
}
}

这段示例代码也有同样的问题,我们想要成对的元素,但使用 enumerated() 去获取索引以便后续操作的时候,我们就需要手动去处理索引,这并没有必要。zip 在这种情况下也适用。

首先,处理容器和第一个元素的约束:

imageViews.first?.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true

接着,我们来把元素拼成一对:

for (left, right) in zip(imageViews, imageViews.dropFirst()) {
left.trailingAnchor.constraint(equalTo: right.leadingAnchor).isActive = true
}

搞定,没有索引值,任何 Sequence 类型都适用,而且更加简洁。

(你也可以把这个拼对的操作封装进 extension 里,我会考虑命名为 .eachPair()

这里介绍一下 enumerated() 的使用姿势。因为你获取到的并非是索引值,而是一个整型,所以当你需要一个数字去对应到每一个元素的时候,就很适合使用 enumerated()。例如,你需要在垂直方向等距摆放多个 view,每一个 view 都需要一个 y,等于某个高度乘以 offset,enumerated() 就很适合。下面是一个例子:

for (offset, view) in views.enumerated() {
view.frame.origin.y = offset * view.frame.height
}

因为这里的 offset 是作为一个数字去使用,enumerated()就可以正常运作。

使用的规则很简单:如果你是想用 enumerated() 去获取索引,那也许会有更好的方式去解决你的问题,如果你是想把它作为一个数字去使用,那就很适合

swift - enumerated()相关推荐

  1. 你需要的大概不是 enumerated

    作者:KHANLOU,原文链接,原文日期:2017-03-28 译者:四娘:校对:Cwift:定稿:CMB Swift 标准库里最容易被滥用的就是 Sequence 的 enumerated() 函数 ...

  2. [Swift]LeetCode218. 天际线问题 | The Skyline Problem

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  3. Swift字典Dictionary快速文档

    Swift Dictionary字典 简述 字典就是通过Key - Value对应关系的数据结构. swift与OC字典区别 ​ 类型: Swift字典是值类型, OC字典类型为引用类型 初始化方法 ...

  4. swift_014(Swift 的控制流)

    //***********swift学习之14--控制流--*************************** // 1.控制流有哪些? /* Swift提供了所有C语言中相似的控制流结构.包括f ...

  5. swift_007(Swift的Array 数组)

    1. 在 Swift 中,如果你用let将数组作为常量来定义,他们就是不可变的,如果用 var 定义为变量他们就是可变的. 作为对比,Foundation 框架中的 NSArray 默认是不可变类型, ...

  6. Swift for循环:用于索引,数组中的元素?

    本文翻译自:Swift for loop: for index, element in array? Is there a function that I can use to iterate ove ...

  7. Swift进阶_第一部分

    介绍 术语 你用,或是不用,术语就在那里,不多不少.你懂,或是不懂,定义就在那里,不偏不倚. 1.'值(value)'是不变的,永久的,它从不会改变,'结构体'和 '枚举'是值类型.当你把一个结构体变 ...

  8. 【译】Swift算法俱乐部-Boyer-Moore字符串搜索

    本文是对 Swift Algorithm Club 翻译的一篇文章. Swift Algorithm Club是 raywenderlich.com网站出品的用Swift实现算法和数据结构的开源项目, ...

  9. Swift: 可变参数

    转自: https://addicechan.github.io/... 在Swift中,命名一个方法参数的时候,如果有多个特定类型的参数,可以直接使用可变参数(Variadic Parameters ...

  10. Swift 3 新特性

    原文:What's New in Swift 3? ,作者:Ben Morrow,译者:kmyhy Swift 3将于今年下半年推出,为Swift开发者们带来了很多核心代码的改变.如果你没有关注过 S ...

最新文章

  1. 掌握深度学习,为什么要用PyTorch、TensorFlow框架?
  2. asp.net core选项配置的研究
  3. 对国内云计算三个现象的思考
  4. SharePoint工作流开发点滴(2) - 开发第一个SharePiont工作流: HelloWorldSequential 的注意事项...
  5. php 5.3.9 漏洞,PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830) 详解
  6. ruby 将字符转数字计算_Ruby程序计算一个数字中的位数
  7. Handler 引起的内存泄露
  8. Python爬取图片时,urllib提示没有属性urlretrieve的问题
  9. 项目管理-项目启动会
  10. javaSocket网络编程
  11. 元宇宙的时代来不及解释了快上车
  12. 国税计算机安全管理制度,武汉市国家税务局关于印发《计算机中心机房管理制度》的通知...
  13. 计算机自动维护有用吗,Win10系统关闭自动维护功能提高系统运行速度
  14. oracle本地归档路径,oracle查看归档日志路径
  15. 全志XR系类的芯片选型
  16. 有奖调研 | 让虚拟照入现实的完美AR开发平台长什么样?
  17. 基于 Web 端的人脸识别身份验证
  18. 小程序记账项目源码-采用云开发
  19. Android分享之“始终”和“仅此一次”
  20. 如何加速播放SWF格式文件——使用Enounce MySpeed轻松实现

热门文章

  1. EXCEL密码清除(破解找回密码)——巧用宏代码
  2. 1234的平方根用计算机怎么算,平方根计算
  3. 微信商户平台所有产品总结
  4. Java String 类型编码转换
  5. 前端原生开发解决方案
  6. word2016文档怎样添加封面?简单技巧!word文档如何设置加入封面?
  7. intel 电脑棒一代linux,拆解:英特尔黑科技——电脑棒
  8. Excel快捷键大全之功能键合集
  9. Latex下划线问题
  10. Photoshop脚本 合并链接图层