KM的博客.

Swift集合源码

字数统计: 1.1k阅读时长: 5 min
2020/04/18

Swift Collections

使用篇

1、Array

数组基本操作

let someArray = [1,2,3,4,5,6]

let first5 = Array(someArray.prefix(3)) // [1,2,3]

数组Array的两种for循环

只遍历value

1
2
3
for item in array {
print(item)
}

快速枚举数组,用元祖(index, value)接收

1
2
3
for (index, value) in array.enumerated() {
print(index, value)
}

array.enumerated() + map 快速枚举

1
2
3
4
5
let nums = [1,2,3,4,5]
let newNums = nums.enumerated().map { (index, num) in
return num * 10
}
print("newNums:\(newNums)")

数组的值倒叙reversed() + enumerated()

//可以用来快速的枚举数组中的内容,并用元组(index, value)接收 public func enumerated() -> EnumeratedSequence>

//可以倒叙数组内容 public func reversed() -> ReversedRandomAccessCollection>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let nums = [5,4,3,2,1]


//1、值倒叙
for item in nums.reversed().enumerated() {
print(item)
}
for (index, item) in nums.reversed().enumerated() {


}
/*
(offset: 0, element: 1)
(offset: 1, element: 2)
(offset: 2, element: 3)
(offset: 3, element: 4)
(offset: 4, element: 5)
*/


-------------------------------------------


// 2、索引+值都是倒叙
for i in nums.enumerated().reversed() {
// print("\(i)")
}
/*
(offset: 4, element: 1)
(offset: 3, element: 2)
(offset: 2, element: 3)
(offset: 1, element: 4)
(offset: 0, element: 5)
*/

数组的索引逆序

1
2
3
for i in (0...(nums.count - 1)).reversed() {
print(i)
}

数组的索引逆序

1、forEach()遍历optional集合会自动过滤nil

1
2
3
4
5
6
7
8
9
let optionalString: [String]? = nil
//使用forEach强制解包option,会过滤
optionalString?.forEach { str in
print("str is (str)")
}
///使用for-in强制解包optional,会crash
for str in optionalString! {
print("str is (str)")
}

2、forEach()和enumerated()的区别?

  • forEach的官方定义
1
2
3
4
5
public func forEach(_ body: (Element) throws -> Void) rethrows {
for element in self {
try body(element)
}
}
  • forEach的使用
1
2
3
ships.forEach {
print("\($0.value) is from \($0.key)")
}

3、enumerated()还是zip()???

我见到 enumerated() 最常用的方式是对一个数组执行 enumerated,使用返回的 offset 来获取另一个数组对应的元素。

1
2
3
4
5
6
for (offset, model) in models.enumerated() {
let viewController = viewControllers[offset]
viewController.model = model
}


虽然这段代码可以正常运作,但前提是 modelsviewControllers 都是 Array 类型,使用整型来作为索引值类型,从 0 开始。另一个前提是这两个数组拥有相同的长度。如果models 的数组长度比 viewControllers 短的话,就会崩溃。我们还多了一个没有实际意义的多余的变量 offset。一个简洁的 Swift 实现方式应该是:

1
2
3
4
5
for (model, viewController) in zip(models, viewControllers) {
viewController.model = model
}


使用zip()加简洁,而且适用于所有 Sequence 类型,而且可以安全地处理不等长的数组。

让我们看看另一个例子,这段代码给第一个 imageView 和它的容器以及每个 imageView 之间添加了一段 autolayout 的约束

1
2
3
4
5
6
7
8
9
10
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 在这种情况下也适用。

首先,处理容器和第一个元素的约束:

1
2
3
imageViews.first?.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true


接着,我们来把元素拼成一对:

1
2
3
4
5
for (left, right) in zip(imageViews, imageViews.dropFirst()) {
left.trailingAnchor.constraint(equalTo: right.leadingAnchor).isActive = true
}


搞定,没有索引值,任何 Sequence 类型都适用,而且更加简洁。

2、字典

Dictionary to JSON string

The dictionary is converted to Data which contains an UTF8 encoded string inside.

1
2
3
4
5
let dictionary = ["nacho": ["1","2","3"]]
let jsonData = try? JSONSerialization.data(withJSONObject: dictionary, options: [])
let jsonString = String(data: jsonData!, encoding: .utf8)
print(jsonString)
{"nacho":["1","2","3"]}

Also it is possible to use .prettyPrinted which is nice for showing the result string to humans, but in reality I almost never use it.

JSON String to Dictionary

The JSON string should be converted to NSData (using UTF8 encoding), then we can create a dictionary from such data.

1
2
3
4
5
let jsonString = "{\"nacho\":[\"1\",\"2\",\"3\"]}"
let jsonData = jsonString.data(using: .utf8)!
let dictionary = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableLeaves)
print(dictionary)
Optional(["nacho": ["1", "2", "3"]])

In JSONReadingOptions there is also .mutableLeaves, .allowFragments, etc but I don’t use them very often (Mutable leaves will create a mutable dictionary which might sound helpful but in reality you want to handle things as few as possible in dictionaries since its information is not always statically typed and programmers are able to add/remove key/values without the compiler knowing about it).

Accessing information from objects created with JSONSerialization.jsonObject

Now, since JSONSerialization.jsonObject returns an object of type Any we need to cast it (according to our needs) to be able to access its information. For example:

1
2
3
4
5
6
7
8
if let personsDictionary = dictionary as? [String: Any] {
print(personsDictionary)
if let numbers = personsDictionary["nacho"] as? [String] {
print(numbers)
}
}
["nacho": ["1", "2", "3"]]
["1", "2", "3"]
CATALOG
  1. 1. Swift Collections
    1. 1.1. 使用篇
    2. 1.2. 1、Array
      1. 1.2.1. 数组基本操作
      2. 1.2.2. 数组Array的两种for循环
      3. 1.2.3. 数组的值倒叙reversed() + enumerated()
      4. 1.2.4. 数组的索引逆序
      5. 1.2.5. 数组的索引逆序
        1. 1.2.5.1. 1、forEach()遍历optional集合会自动过滤nil
        2. 1.2.5.2. 2、forEach()和enumerated()的区别?
        3. 1.2.5.3. 3、enumerated()还是zip()???
    3. 1.3. 2、字典
      1. 1.3.1. Dictionary to JSON string
      2. 1.3.2. JSON String to Dictionary
      3. 1.3.3. Accessing information from objects created with JSONSerialization.jsonObject