Array
Array
是有序的,支持随机读写的集合类型@frozen struct Array<Element>

// 创建空的Array, 类型推 断
let array1 = [Int]()
var array2 = Array<Int>()
// 创建空的Array, 指定类型
var array3 : [Int] = []
// 通过列表初始化
var array4 = [1,2,3,4,5]
// 调用init方法初始化
var array5 = Array(repeating:0, count:3)
+
,append(_:)
可以在数组尾部添加元素insert(_:,at:)
在索引指定的位置插入元素array1.append(11)
array1 += [13,12]
array1.insert(13,at:0)
remove(at:)
删除索引指定位置的元素removeLast()
删除数组中的最后一项//
array1.remove(at:5)
// Can't remove last element from an empty collection:
array1.removeLast()
使用下标法访问
Array
中的元素array1[0]
array1[1] = 12
// 下标法可以使用区间运算符
array1[1...3] = [2,3,4]
可以直接使用
for-in
循环遍历数组for value in array1 {
print("\(value)")
}
如果同时需要每个数据项的值和索引值,可以使用
enumerated()
方法来进行数组遍历。enumerated()
返回一个由索引值和数据值组成的元组数组。for (index, value) in shoppingList.enumerated() {
print("Item \(String(index + 1)): \(value)")
}
如果你试图通过越界索引来执行访问或者修改数据的操作,会引发一个运行时错误。此时可以使用索引值和数组的 count 属性进行比较来在使用该索引之前检验其是否有效。除了当 count 等于 0 时(说明这是个空数组),最大索引值一直是 count - 1,因为数组都是零起索引。
每个数组都会预留一定数量的内存空间去保存元素。当在数组中添加元素且超出预留的数量;数组会申请一块更大的内存空间,并将元素复制到新的内存空间中。
新的内存空间是旧空间的数倍大小。指数级的增长策略意味着多次append操作的平均性能是实时的。触发内存充分配的append 操作有一定的性能消耗,但是数组的容量的逐渐增大,内存分配将会发生的更少。
如果预先知道需要存储的元素数量,可以在添加元素之前调用
reserveCapacity(_:)
避免内存重分配。capacity
和 count
属性可以用于计算可用容量。对于大部分元素类型,存储区域是一个连续的内存空间。对于元素类型是 class 或者 @objc protocol 的数组,存储区域可以是一个连续的内存空间或者NSArray的对象。
Array 是struct类型,也就是值类型。Array对象的每一个拷贝之间都是独立的,修改一个拷贝并不会影响其他拷贝。
如果 Array 的元素类型是值类型,那不仅是Array对象的每个拷贝是独立的,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]"
如果 Array 的元素类型是引用类型,尽管Array对象的每个拷贝是独立的,Array对象的每个拷贝对应的元素是浅拷贝,指向同一个引用类型对象。
// 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"
标准库中的许多集合包括Array都使用了 写时拷贝 优化。 Array 的多个拷贝共享同一块存储空间,直到某一个拷贝被修改。
当Array的某个拷贝首次被修改时,会复制出一块新的独属于该拷贝的存储空间,然后再修改;之后再修改就不再有申请新的存储空间的开销了。
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 对象之间相关转换,可以使用类型声明运算符(
as
)来实现桥接。桥接的前提是元素的类型必须是class
或者@objc protocol
或者Foundation类型
。有以下的示例:
colors
是 Array<String>
的数组,元素类型为 String
, String
是一个Foundation类型,可以桥接;moreColors
是 Array<String?>
, 元素类型为 String?
, String?
本质上是枚举类型,不是class
或者@objc protocol
或者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)当元素类型为
class
或者 @objc protocol
, NSArray
桥接为 Array
首先调用 copy(with:)
方法获得一个可变的拷贝数组,然后执行额外的Swift保存操作,将会消耗O(1)的时间复杂度。如果是 NSMutableArray
对象桥接为Array
,copy(with:)
通常会在O(1)时间内返回同一个数组对象 ,否则copy的性能将是不确定的。如果copy(with:)
返回同一个数组对象,NSArray
和 Array
共享同一块支持写实拷贝的存储空间。当元素类型为Foundation中的非class类型,
Array
桥接为 NSArray
的时间复杂度和空间复杂度都是 O(n)当元素类型是Foundation中的非class类型,
NSArray
桥接为 Array
会在 O(n) 的时间复杂度内将元素拷贝到一块连续存储中。