Swift-技巧(七)重识 Array_swift 数组快速查找-程序员宅基地

技术标签: array  Swift  ios  swift  

摘要

iOS 开发,尤其是从 OC 转换到 Swift,对 Array 需要重新了解,Swift 中保留了什么属性,增加了什么属性,内存存储是什么情况等等,了解了这些,在使用 Array 的时候可以更符合 Swift 的思想,也方便了自己。

Array 是应用程序中最常用的数据类型之一,可以使用 Array 来处理应用程序中的数据。使用 Array 类型来保存单一类型的元素。数组可以存储任何类型的元素—— 从 Int 到 String,甚至是 Class,但是数组中元素必须是同一类型

Swift 中可以使用数组字面量创建数组,若没有定义数组中元素类型,Swift 会自动推断数组中元素的类型。例如:

// 数组元素类型为 Int
let numbers = [1, 2, 3]

// 数组元素类型为 String
let names = ["li", "zhang"]

也可以通过在声明中指定数组的元素类型来创建一个空数组,例如:

// 元素类型为 Int 的空数组
var emptyInt: [Int] = []

// 元素烈性为 Double 的空数组
var emptyDouble: Array<Double> = Array()

如果需要固定数量的默认值来初始化数组,可以使用 Array(repeating:count:) 创建:

var digitCounts = Array(repeating: 1, count: 3)
print(digitCounts)
// Prints "[1, 1, 1]"

访问数组元素

当需要对数组所有元素执行操作时,可以使用 for-in 来循环遍历数组的内容。

for name in names {
    
	print(name)
}
// Print "li"
// Print "zhang"

这里可以使用 isEmpty 属性快速检查数组中是否包含任何元素,等同于使用 count 属性查找数组中的元素数量,并判断是否为 0

print(numbers.isEmpty) // Print false
print(numbers.count == 0) // Print false

使用 firstlast 属性可以安全地访问数组的第一个元素和最后一个元素,如果数组为空,就返回 nil

print(number.first) // Print "1"
print(number.last) // Print "3"

print(emptyInt.first, emptyInt.last, separator: ", ")
// Prints "nil, nil"

可以通过下标访问数组中的单个元素,非空数组的第一个元素下标为 0,数组的下标范围从 0 到数组的 count(不包括 count)。使用负数、等于或者大于 count 的索引,会引发运行时错误,比如:

print(number[0], number[2], separator: ", ")
// Prints "1, 3"

print(emptyInt[0])
// Triggers runtime error: Index out of range

添加和删除元素

假如你需要存储一个入职员工的名字列表。在这期间,你需要添加和删除名字。

var staffs = ["zhang", "wang", "li"]

使用 append(_:) 方法将单个元素添加到数组的尾部。使用 append(contentsOf:) 可以同时添加多个元素,参数可以是另外一个数组或者元素类型相同的序列

staffs.append("zhao")
staffs.append(contentsOf: ["song", "suo"])
// ["zhang", "wang", "li", "zhao", "song", "suo"]

你也可以在数组中间添加新的元素,使用 insert(_:at:) 函数插入单个元素,使用 insert(contentsOf:at:) 方法插入另一个集合或者数组字面量的多个元素。索引处和索引后面的元素都往后移,腾出空间。

staffs.insert("ding", at: 3)
// ["zhang", "wang", "li", "ding", "zhao", "song", "suo"] 

要从数组中删除元素,可以使用 remove(at:)removeSubrange(_:)removeLast() 函数。

staffs.remove(at: 0)
// ["wang", "li", "ding", "zhao", "song", "suo"] 

staffs.removeLast()
// ["wang", "li", "ding", "zhao", "song"] 

通过将新值赋值给下标,达到用新值替换现有的元素的效果

if let i = staffs.firstIndex(of: "ding") {
    
	staffs[i] = "bian"
}
// ["wang", "li", "bian", "zhao", "song"]  

增加数组的大小(重点)

每个数组都会保留特定数量的内存来保存其内容。当向数组中添加元素时,该数组超过其预留的容量,该数组就会分配更大的内存空间,并将它的所有元素赋值到新的存储空间。添加一个元素的时间是固定的,相对来说性能是平均的。但是重新分配的操作会带来性能成本,随着数组的增大,这些操作发生的频率也会越来越低。

如果知道大约需要存储多少元素,在添加到元素之前使用 reserveCapacity(_:) 函数,避免中间重新分配。使用 countcapacity 属性来确定数组在不分配更大存储空间的情况下还可以存储多少元素。

var array = [1, 2]
array.reserveCapacity(20)

对于大多数 Element 类型的数组,存储区域是一个连续的内存,对于元素类型是 class 或者 objc protocol 类型的数组,该存储可以是一个连续的内存,或者 NSArray 的实例。因为 NSArray 的任何子类都可以是一个 Array,所以这种情况下不能保证是内存块或者 NSArray 的实例

修改数组副本(重点)

每个数组都有一个独立的存储空间,存储着数组中包含的所有元素的值。对于简单类型,如整数或者其他结构,当更改一个数组中的值时,该元素的值不会在数组的任何副本中更改。例如:

var numbers = [4, 5, 6]
var numbersCopy = numbers

numbers[0] = 9
print(numbers)
// Prints "[9, 5, 6]"
print(numbersCopy)
// Prints "[4, 5, 6]"

如果数组的元素是类的实例。在本例中,存储在数组中的值是对存在于数组之外的对象引用。如果更改一个数组中对象的引用 ,则只有该数组有对新对象的引用。但是,如果两个数组包含对同一个对象的引用,则可以从两个数组中看到该对象属性的更改,例如:

class InterR {
    
	var value = 10
}

var integers1 = [InterR(), InterR()]
var integers2 = integers1

integers1[0].value = 100
print(integers2[0].value)
// Prints "100"

integers1[0] = InterR()
print(integers1[0].value)
// Prints "10"
print(integers2[0].value)
// Prints "100"

和标准库中的所有可变大小集合一样,数组也使用 copy-on-write 优化。多个副本共享同一个存储空间,直到修改其中一个副本为止。当发生这种情况时,被修改的数组会创建新的存储空间存储,然后在对应的位置修改。copy-on-write 优化可以减少复制的数量。

这就说明,如果一个数组与其他副本共享存储空间,对该数组的第一次更改操作会导致复制该数组的成本。之后就可以作为唯一的拥有者来对它进行操作。

下面例子中,将创建一个数组和两个共享相同存储的副本。当原始数组被修改时,它会在修改前对其存储进行唯一复制。然后进行修改。而两个副本继续共享原来的存储空间。

var numbers = [7, 8, 9]
var copy1 = numbers
var copy2 = numbers

numbers[0] = 100
numbers[1] = 200
numbers[2] = 300

// numbers: [100, 200, 300]
// copy1 和 copy 2 : [7, 8, 9]

Array 和 NSArray 之间转换(重点)

当需要访问 NSArray 实例的 API 时,使用类型转换操作符 as 来转换 Array 实例。为了保证转换成功,数组的 Element 类型必须是一个 class 类型,一个 @objc protocol 或者一个连接到 Foundation 类型。

下面例子展示了如何使用 write(to:atomically:) 函数将一个 Array 实例连接到 NSArray。在这个例子中,colors 数组可以转换到 NSArray,因为 colors 数组的 String 类型元素转换到 NSString。另一个,编译器阻止转换 moreColors 数组,因为它的 Element 类型是 Optional, 它不能转换 Foundation 类型。

let colors = ["periwinkle", "rose", "moss"]
let moreColors: [String?] = ["ochre", "pine"]

let url = URL(fileURLWithPath: "names.plist")
(colors as NSArray).write(to: url, atomically: true)
// true

(moreColors as NSArray).write(to: url, atomically: true)
// error: cannot convert value of type '[String?]' to type 'NSArray'

如果数组的元素已经是 class@objc protocol 的实例,那么从 Array 到 NSArray 的转换只需要 O(1) 时间和空间,否则,它需要 O(n) 个时间和空间

当目标数组的元素类型是一个 class@objc protocol 时,从 NSArray 到 Array 的转换首先调用数组上的 copy(with:) 函数来得到一个不可变的副本,然后执行额外的 Swift bookkeeping work,需要 O(1) 时间。对于已经不可变的 NSArray 实例,copy(with:) 通常在 O(1) 时间内返回相同的数组,否则,复制性能将不确定。如果 copy(with:) 返回相同的数组,NSArray 和 Array 的实例使用相同的 copy-on-write 优化共享存储空间,当两个 array 实例共享存储空间时,使用相同的优化。

当目标数组的元素类型是转换 Foundation 类型的非 class 类型时,从 NSArray 到 Array 的转换会在 O(n) 时间内把元素转换复制到连续的存储空间。比如,从 NSArray 转换到 Array 执行这样的复制。当访问 Array 实例的元素时,不需要进一步的转换。

注意

ContiguousArrayArraySlice 类型没有转换,这些类型的实例总是有一个连续的内存空间作为它的的存储。

题外话

时间仓促,说的东西可能不全面,在你查看的过程中遇到什么问题,评论区给我留言,我会尽快回复

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43636096/article/details/121501342

智能推荐

为什么eMule总是未连接到服务器-程序员宅基地

文章浏览阅读1k次。<一>安装和版本问题1) eMule对Windows有什么要求?eMule能在Windows 95版本以上的Windows操作系统下运行。1个好的P2P软件需要好的拨号网络的支持,所以Windows 98和Windows ME的比较差网络运行情况可能会影响eMule的发挥;相对来说Windows 2000和Windows XP更适合使用eMule。2) 弹出错误信息说oleacc.dl..._emule v0.50b 最新服务器未连接

14 种编程语言书写关机脚本,真香_如何写强制关机脚本-程序员宅基地

文章浏览阅读2w次,点赞19次,收藏49次。批处理版本C 语言版本C++ 语言版本JAVA 语言版本C# 语言版本Python 语言版本NodeJS 语言版本PHP 语言版本Perl 语言版本Go 语言版本VB 语言版本SQL 语言版本树莓派 版本易语言 版本期待评论区故事的起源,有个家伙发来一个 BAT 的关机脚本,我顺手给改成了 八种语言的。_如何写强制关机脚本

docker compose搭建elasticsearch7集群_insufficient buffer remaining for aead cipher frag-程序员宅基地

文章浏览阅读4.1k次,点赞2次,收藏7次。一、集群介绍系统环境:Centos7.5服务器节点:主机名 IP hadoop03 192.168.1.153 hadoop04 192.168.1.154 hadoop05 192.168.1.155 二、环境准备1、安装docker:略过2、安装docker compose1)使用官方推荐方式(此方式需服务器翻外网)curl -L "https://github.com/docker/compose/releases/download_insufficient buffer remaining for aead cipher fragment (2). needs to be more

Debian10安装部署DNS服务-正向解析篇_debian10安装powerdns-程序员宅基地

文章浏览阅读6k次,点赞7次,收藏39次。1、服务安装1.1、服务安装执行下面的命令安装apt install -y bind9 dnsutils1.2、配置文件作用服务安装完成之后,执行下面的命令查看配置文件列表ls -l /etc/bind然后得到下面的信息root@debian:~# ls -l /etc/bind总用量 48-rw-r--r-- 1 root root 2761 5月 18 16:02 bind.keys-rw-r--r-- 1 root root 237 5月 18 16:02 db.0_debian10安装powerdns

Cocos2d-x支持多种动画格式_cocos2dx 动画类型-程序员宅基地

文章浏览阅读346次,点赞7次,收藏10次。DragonBones是一个免费的2D骨骼动画编辑器,可以导出为Cocos2d-x兼容的格式。在Cocos2d-x中,你可以使用dragonbones-cocos2dx库来加载和播放DragonBones动画。Spine是一种2D骨骼动画工具,可以让你创建复杂的动画效果。在Cocos2d-x中,你可以使用spine-cocos2dx库来加载和播放Spine动画。CCAnimation:Cocos2d-x自带的动画类,用于创建基于Sprite帧的动画。你可以使用它来控制动画的播放和停止。_cocos2dx 动画类型

如何使用UUP从windows更新服务器下载windows10原版镜像_uup_download_windows.cmd-程序员宅基地

文章浏览阅读832次,点赞11次,收藏11次。UUP是指Windows 10中的一种更新技术,全称为Unified Update Platform。UUP的目标是提供更快、更高效的更新体验,它通过增量更新的方式来更新操作系统,只下载和安装实际变化的部分,而不是整个更新包。这样可以节省带宽和时间,加快更新速度。UUP还支持多种设备类型,包括PC、手机、Hololens等。制作完成后的镜像在根目录,制作的过程时间取决于电脑的性能。选择windows10版本,可以看到所有的版本列表。选择下载并转换为iso文件,点击创建下载包。选择需要的版本,下一步。_uup_download_windows.cmd

随便推点

MySQL 之多表连查_mysql连表查询-程序员宅基地

文章浏览阅读5.8k次。连接是关系数据库模型的主要特点,连接查询是关系数据库中最主要的查询,主要包括内连接、外连接等.通过连接运算符可以实现多个表查询,在关系数据库管理系统中,表建立时各数据之间的关系不必确定,常把一个实体的所有信息存放在一个表中.当查询数据时,通过连接操作查询出存放在多个表中的不同实体的信息.当两个或多个表中存在相同意义的字段时,便可以通过这些字段对不同的表进行连接查询._mysql连表查询

利用JWT Token配合Redis实现单点登录并进行Token的缓存验证唯一性_使用redis实现jwt令牌的单点登录功能-程序员宅基地

文章浏览阅读2.1k次。以上为一个基础的使用Spring Boot、MyBatis、Redis和JWT实现用户登录认证的完整示例。具体实现中可以根据需求进行更改和优化。_使用redis实现jwt令牌的单点登录功能

机器学习&人工智能:大牛带你回顾2016,展望2017-程序员宅基地

文章浏览阅读206次。雷锋网按:2016即将过去,针对机器学习和人工智能领域在2016年取得的重大进展,以及2017年可能出现的新趋势,外媒KDnuggets咨询了12位业内顶级专家,汇集了他们的观点并整理成文,其中AlphaGo战胜李世石成为今年的标志性事件。雷锋网对全文进行了编译,未经许可,不得转载。1. Yaser Abu-Mostafa,加州理工学院顾问2016..._机器学习公平性展望

html5图片无限循环播放,原生js实现无限循环轮播图效果-程序员宅基地

文章浏览阅读3.6k次。知识要点1.实现无限循环的原理:以偏移的距离来判断是否跳回第一张和最后一张也可以利用循环判断图片的当前索引值var newLeft=parseInt(list.style.left)+offset;//当前的偏移量+下一次的偏移量=新的偏移量list.style.left=newLeft+"px";//当前的偏移值=新的偏移值//以偏移的距离来判断是否跳回第一张和最后一张if(newLeft>..._html5图片循环滚动

win10更新KB5034441版本,报错0x80070643_kb5034441更新失败-程序员宅基地

文章浏览阅读567次,点赞23次,收藏20次。当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。网安所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。,一般来说恢复分区的前一个分区是系统分区,也即。我这里有星号(*),是GPT类型的。