当前位置: 首页>>编程示例 >>用法及示例精选 >>正文


Swift Array用法及代码示例

结构

Array

一个有序的、随机访问的集合。

声明

@frozen struct Array<Element>

概述

数组是应用程序中最常用的数据类型之一。您使用数组来组织应用程序的数据。具体来说,您使用 Array 类型来保存单一类型的元素,即数组的 Element 类型。数组可以存储任何类型的元素——从整数到字符串再到类。

Swift 使使用数组字面量在代码中创建数组变得很容易:只需用方括号将逗号分隔的值列表括起来。在没有任何其他信息的情况下,Swift 会创建一个包含指定值的数组,自动推断数组的 Element 类型。例如:


// An array of 'Int' elements
let oddNumbers = [1, 3, 5, 7, 9, 11, 13, 15]


// An array of 'String' elements
let streets = ["Albemarle", "Brandywine", "Chesapeake"]

您可以通过在声明中指定数组的Element 类型来创建一个空数组。例如:


// Shortened forms are preferred
var emptyDoubles: [Double] = []


// The full type name is also allowed
var emptyFloats: Array<Float> = Array()

如果您需要使用固定数量的默认值预初始化的数组,请使用 Array(repeating:count:) 初始化程序。


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

访问数组值

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


for street in streets {
    print("I don't live on \(street).")
}
// Prints "I don't live on Albemarle."
// Prints "I don't live on Brandywine."
// Prints "I don't live on Chesapeake."

使用isEmpty 属性快速检查数组是否有任何元素,或使用count 属性查找数组中元素的数量。


if oddNumbers.isEmpty {
    print("I don't know any odd numbers.")
} else {
    print("I know \(oddNumbers.count) odd numbers.")
}
// Prints "I know 8 odd numbers."

使用 firstlast 属性可安全访问数组的第一个和最后一个元素的值。如果数组为空,则这些属性为 nil


if let firstElement = oddNumbers.first, let lastElement = oddNumbers.last {
    print(firstElement, lastElement, separator: ", ")
}
// Prints "1, 15"


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

您可以通过下标访问单个数组元素。非空数组的第一个元素始终位于索引零处。您可以使用从零到但不包括数组计数的任何整数为数组下标。使用等于或大于 count 的负数或索引会触发运行时错误。例如:


print(oddNumbers[0], oddNumbers[3], separator: ", ")
// Prints "1, 7"


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

添加和删除元素

假设您需要存储已注册您正在教授的课程的学生姓名列表。在注册期间,您需要在学生添加和删除类时添加和删除姓名。


var students = ["Ben", "Ivy", "Jordell"]

要将单个元素添加到数组的末尾,请使用 append(_:) 方法。通过将另一个数组或任何类型的序列传递给 append(contentsOf:) 方法,同时添加多个元素。


students.append("Maxime")
students.append(contentsOf: ["Shakia", "William"])
// ["Ben", "Ivy", "Jordell", "Maxime", "Shakia", "William"]

您可以通过对单个元素使用 insert(_:at:) 方法并使用 insert(contentsOf:at:) 从另一个集合或数组字面量插入多个元素来在数组中间添加新元素。该索引和后面的索引处的元素被移回以腾出空间。


students.insert("Liam", at: 3)
// ["Ben", "Ivy", "Jordell", "Liam", "Maxime", "Shakia", "William"]

要从数组中删除元素,请使用 remove(at:)removeSubrange(_:)removeLast() 方法。


// Ben's family is moving to another state
students.remove(at: 0)
// ["Ivy", "Jordell", "Liam", "Maxime", "Shakia", "William"]


// William is signing up for a different class
students.removeLast()
// ["Ivy", "Jordell", "Liam", "Maxime", "Shakia"]

您可以通过将新值分配给下标来用新值替换现有元素。


if let i = students.firstIndex(of: "Maxime") {
    students[i] = "Max"
}
// ["Ivy", "Jordell", "Liam", "Max", "Shakia"]

增加数组的大小

每个数组都会保留特定数量的内存来保存其内容。当您向数组添加元素并且该数组开始超出其保留容量时,该数组会分配更大的内存区域并将其元素复制到新存储中。新存储是旧存储大小的倍数。这种指数增长策略意味着追加一个元素在恒定时间内发生,平均许多追加操作的性能。触发重新分配的追加操作有性能成本,但随着阵列变大,它们发生的频率越来越低。

如果您知道大约需要存储多少元素,请在追加到数组之前使用reserveCapacity(_:) 方法以避免中间重新分配。使用capacitycount 属性来确定数组可以存储多少元素而不分配更大的存储空间。

对于大多数Element 类型的数组,此存储是一个连续的内存块。对于 Element 类型为类或 @objc 协议类型的数组,此存储可以是连续的内存块或 NSArray 的实例。因为 NSArray 的任意子类都可以成为 Array ,所以在这种情况下不能保证表示或效率。

修改数组的副本

每个数组都有一个独立的值,包括其所有元素的值。对于整数和其他结构等简单类型,这意味着当您更改一个数组中的值时,该元素的值在数组的任何副本中都不会更改。例如:


var numbers = [1, 2, 3, 4, 5]
var numbersCopy = numbers
numbers[0] = 100
print(numbers)
// Prints "[100, 2, 3, 4, 5]"
print(numbersCopy)
// Prints "[1, 2, 3, 4, 5]"

如果数组中的元素是类的实例,则语义是相同的,尽管它们起初可能看起来不同。在这种情况下,存储在数组中的值是对位于数组外部的对象的引用。如果您更改对一个数组中的对象的引用,则只有该数组具有对新对象的引用。但是,如果两个数组包含对同一个对象的引用,您可以从两个数组中观察到该对象属性的变化。例如:


// An integer type with reference semantics
class IntegerReference {
    var value = 10
}
var firstIntegers = [IntegerReference(), IntegerReference()]
var secondIntegers = firstIntegers


// Modifications to an instance are visible from either array
firstIntegers[0].value = 100
print(secondIntegers[0].value)
// Prints "100"


// Replacements, additions, and removals are still visible
// only in the modified array
firstIntegers[0] = IntegerReference()
print(firstIntegers[0].value)
// Prints "10"
print(secondIntegers[0].value)
// Prints "100"

与标准库中的所有 variable-size 集合一样,数组使用 copy-on-write 优化。阵列的多个副本共享相同的存储,直到您修改其中一个副本。发生这种情况时,正在修改的阵列将其存储替换为自身唯一拥有的副本,然后对其进行原地修改。有时会应用可以减少复制量的优化。

这意味着如果一个数组与其他副本共享存储,则对该数组的第一次变异操作会产生复制该数组的成本。作为其存储的唯一所有者的阵列可以就地执行变异操作。

在下面的示例中,创建了一个numbers 数组以及共享同一存储的两个副本。当原始numbers 数组被修改时,它会在进行修改之前制作其存储的唯一副本。对numbers 进行了进一步修改,而两个副本继续共享原始存储。


var numbers = [1, 2, 3, 4, 5]
var firstCopy = numbers
var secondCopy = numbers


// The storage for 'numbers' is copied here
numbers[0] = 100
numbers[1] = 200
numbers[2] = 300
// 'numbers' is [100, 200, 300, 4, 5]
// 'firstCopy' and 'secondCopy' are [1, 2, 3, 4, 5]

Array 和 NSArray 之间的桥接

当您需要访问需要 NSArray 实例而不是 Array 中的数据的 API 时,请使用 type-cast 运算符 (as) 来桥接您的实例。为了使桥接成为可能,数组的 Element 类型必须是类、@objc 协议(从 Objective-C 导入的协议或标有 @objc 属性的协议)或桥接到 Foundation 的类型类型。

以下示例显示如何将Array 实例桥接到NSArray 以使用write(to:atomically:) 方法。在此示例中,colors 数组可以桥接到 NSArray,因为 colors 数组的 String 元素桥接到 NSString 。另一方面,编译器会阻止桥接 moreColors 数组,因为它的 Element 类型是 Optional<String> ,它会将 not 桥接到 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'

如果数组的元素已经是类或 @objc 协议的实例,则从 Array 桥接到 NSArray 需要 O(1) 时间和 O(1) 空间;否则,需要 O(n) 时间和空间。

当目标数组的元素类型是类或@objc协议时,从NSArray桥接到Array首先调用数组上的copy(with:)(Objective-C中的- copyWithZone:)方法来获取不可变副本和然后执行额外的 Swift 簿记工作,需要 O(1) 时间。对于已经不可变的NSArray 的实例,copy(with:) 通常在 O(1) 时间内返回相同的数组;否则,复制性能未指定。如果 copy(with:) 返回相同的数组,则 NSArrayArray 的实例使用与 Array 的两个实例共享存储时使用的相同 copy-on-write 优化来共享存储。

当目标数组的元素类型是桥接到 Foundation 类型的非类类型时,从 NSArray 桥接到 Array 会在 O(n) 时间内将元素的桥接副本复制到连续存储。例如,从NSArray 桥接到Array<Int> 会执行这样的复制。访问Array 实例的元素时不需要进一步的桥接。

可用版本

iOS 8.0+, iPadOS 8.0+, macOS 10.10+, Mac Catalyst 13.0+, tvOS 9.0+, watchOS 2.0+

相关用法


注:本文由纯净天空筛选整理自apple.com大神的英文原创作品 Array。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。