热门标签 | HotTags
当前位置:  开发笔记 > IOS > 正文

swiftenumerated()

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

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..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 编程中,遇到错误提示“一元运算符 '!' 不能应用于 '()' 类型的操作数”,通常是因为尝试对没有返回值的方法或函数应用逻辑非运算符。本文将详细解释该错误的原因,并提供解决方案。 ... [详细]
  • 本文介绍了在Windows Server 2003环境下,使用XAMPP Lite 1.7.1和DotProject 2.1.3时遇到的日历和甘特图中文乱码问题的解决方案。通过修改相关文件和配置,可以有效解决这些问题。 ... [详细]
  • 本文探讨如何在 C# 中将 If 语句中检索到的结果保存到一个变量中,以提高代码的可读性和可维护性。 ... [详细]
  • 本次考试于2016年10月25日上午7:50至11:15举行,主要涉及数学专题,特别是斐波那契数列的性质及其在编程中的应用。本文将详细解析考试中的题目,并提供解题思路和代码实现。 ... [详细]
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
  • 本文详细介绍了如何准备和安装 Eclipse 开发环境及其相关插件,包括 JDK、Tomcat、Struts 等组件的安装步骤及配置方法。 ... [详细]
  • 本文详细介绍如何利用已搭建的LAMP(Linux、Apache、MySQL、PHP)环境,快速创建一个基于WordPress的内容管理系统(CMS)。WordPress是一款流行的开源博客平台,适用于个人或小型团队使用。 ... [详细]
  • 在现代Web应用中,当用户滚动到页面底部时,自动加载更多内容的功能变得越来越普遍。这种无刷新加载技术不仅提升了用户体验,还优化了页面性能。本文将探讨如何实现这一功能,并介绍一些实际应用案例。 ... [详细]
  • Hybrid 应用的后台接口与管理界面优化
    本文探讨了如何通过优化 Hybrid 应用的后台接口和管理界面,提升用户体验。特别是在首次加载 H5 页面时,为了减少用户等待时间和流量消耗,介绍了离线资源包的管理和分发机制。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • Python处理Word文档的高效技巧
    本文详细介绍了如何使用Python处理Word文档,涵盖从基础操作到高级功能的各种技巧。我们将探讨如何生成文档、定义样式、提取表格数据以及处理超链接和图片等内容。 ... [详细]
  • Windows 7 64位系统下Redis的安装与PHP Redis扩展配置
    本文详细介绍了在Windows 7 64位操作系统中安装Redis以及配置PHP Redis扩展的方法,包括下载、安装和基本使用步骤。适合对Redis和PHP集成感兴趣的开发人员参考。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 简化报表生成:EasyReport工具的全面解析
    本文详细介绍了EasyReport,一个易于使用的开源Web报表工具。该工具支持Hadoop、HBase及多种关系型数据库,能够将SQL查询结果转换为HTML表格,并提供Excel导出、图表显示和表头冻结等功能。 ... [详细]
  • 离线安装Grafana Cloudera Manager插件并监控CDH集群
    本文详细介绍如何离线安装Cloudera Manager (CM) 插件,并通过Grafana监控CDH集群的健康状况和资源使用情况。该插件利用CM提供的API接口进行数据获取和展示。 ... [详细]
author-avatar
HIGO
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有