當前位置: 首頁>>編程示例 >>用法及示例精選 >>正文


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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。