【iOS】Swift基础语法(控制流、集合、操作符)

旨在快速打通iOS开发流程

By yesmore on 2022-11-25
阅读时间 11 分钟
文章共 2.1k
阅读量

本章内容概览:Swift中的控制流、集合(数组、Set、字典)

上一节:【iOS】02_Swift基础语法(类与结构体、函数式)

下一节:【iOS】04_Swift基础语法(操作符)

同系列文章请查看:快乐码元 - iOS篇

Ⅰ.控制流

1.If 语句

1.1 if…else

1
2
3
4
5
6
let s = "hi"
if s.isEmpty {
print("String is Empty")
} else {
print("String is \(s)")
}

1.2 三元条件

1
s.isEmpty ? print("String is Empty again") : print("String is \(s) again")

1.3 if let-else

1
2
3
4
5
6
7
8
9
10
11
12
func f(s: String?) {
if let s1 = s {
print("s1 is \(s1)")
} else {
print("s1 is nothing")
}
// nil-coalescing
let s2 = s ?? "nothing"
print("s2 is \(s2)")
}
f(s: "something")
f(s: nil)

1.3 if case let

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
enum E {
case c1(String)
case c2([String])

func des() {
switch self {
case .c1(let string):
print(string)
case .c2(let array):
print(array)
}
}
}

E.c1("enum c1").des()
E.c2(["one", "two", "three"]).des()

2.Guard 语句

更好地处理异常情况

2.1 guard

1
2
3
4
5
6
7
8
9
func f1(p: String) -> String {
guard p.isEmpty != true else {
return "Empty string."
}
return "String \(p) is not empty."
}

print(f1(p: "")) // Empty string.
print(f1(p: "lemon")) // String lemon is not empty.

2.2 guard let

1
2
3
4
5
6
7
8
9
func f2(p1: String?) -> String {
guard let p2 = p1 else {
return "Nil."
}
return "String \(p2) is not nil."
}

print(f2(p1: nil)) // Nil.
print(f2(p1: "lemon")) // String lemon is not nil.

3.For-in 遍历

3.1 基本遍历数组

1
2
3
4
let a = ["one", "two", "three"]
for str in a {
print(str)
}

3.2 使用下标范围

1
2
3
for i in 0..<10 {
print(i)
}

3.3 使用 enumerated

1
2
3
for (i, str) in a.enumerated() {
print("第\(i + 1)个是:\(str)")
}

3.4 for in where

1
2
3
for str in a where str.prefix(1) == "t" {
print(str)
}

字典 for in,遍历是无序的:

1
2
3
4
5
6
7
8
let dic = [
"one": 1,
"two": 2,
"three": 3
]
for (k, v) in dic {
print("key is \(k), value is \(v)")
}

3.5 stride

1
2
3
4
5
6
7
8
9
10
11
for i in stride(from: 10, through: 0, by: -2) {
print(i)
}
/*
10
8
6
4
2
0
*/

4.While 语句

4.1 while

1
2
3
4
5
var i1 = 10
while i1 > 0 {
print("positive even number \(i1)")
i1 -= 2
}

4.2 repeat while

1
2
3
4
5
var i2 = 10
repeat {
print("positive even number \(i2)")
i2 -= 2
} while i2 > 0

使用 break 结束遍历,使用 continue 跳过当前作用域,继续下个循环

4.3 Switch 语句

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
func f1(pa: String, t:(String, Int)) {
var p1 = 0
var p2 = 10
switch pa {
case "one":
p1 = 1
case "two":
p1 = 2
fallthrough // 继续到下个 case 中
default:
p2 = 0
}
print("p1 is \(p1)")
print("p2 is \(p2)")

// 元组
switch t {
case ("0", 0):
print("zero")
case ("1", 1):
print("one")
default:
print("no")
}
}

f1(pa: "two", t:("1", 1))
/*
p1 is 2
p2 is 0
one
*/

// 枚举
enum E {
case one, two, three, unknown(String)
}

func f2(pa: E) {
var p: String
switch pa {
case .one:
p = "1"
case .two:
p = "2"
case .three:
p = "3"
case let .unknown(u) where Int(u) ?? 0 > 0 : // 枚举关联值,使用 where 增加条件
p = u
case .unknown(_):
p = "negative number"
}
print(p)
}

f2(pa: E.one) // 1
f2(pa: E.unknown("10")) // 10
f2(pa: E.unknown("-10")) // negative number

Ⅱ.集合

1.数组

数组是有序集合

1
2
3
4
var a0: [Int] = [1, 10]
a0.append(2)
a0.remove(at: 0)
print(a0) // [10, 2]

1.1 difference

找两个集合的不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let dif = a1.difference(from: a2) 
for c in dif {
switch c {
case .remove(let o, let e, let a):
print("offset:\(o), element:\(e), associatedWith:\(String(describing: a))")
case .insert(let o, let e, let a):
print("offset:\(o), element:\(e), associatedWith:\(String(describing: a))")
}
}

/*
remove offset:1, element:four, associatedWith:nil
insert offset:0, element:one, associatedWith:nil
insert offset:1, element:two, associatedWith:nil
*/

let a3 = a2.applying(dif) ?? [] // 可以用于添加删除动画
print(a3) // ["one", "two", "three"]

swift的 diffing 算法在这 http://www.xmailserver.org/diff2.pdf

swift实现在 swift/stdlib/public/core/Diffing.swift

dif 有第三个 case 值 .insert(let offset, let element, let associatedWith) 可以跟踪成对的变化,用于高级动画。

1.2 从数组中随机取一个元素

1
print(a0.randomElement() ?? 0)

1.3 数组排序

1
2
3
4
5
6
7
8
9
10
11
struct S1 {
let n: Int
var b = true
}

let a4 = [
S1(n: 1),
S1(n: 10),
S1(n: 3),
S1(n: 2)
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14

let a5 = a4.sorted { i1, i2 in
i1.n < i2.n
}
for n in a5 {
print(n)
}
/// S1(n: 1)
/// S1(n: 2)
/// S1(n: 3)
/// S1(n: 10)

let a6 = [1,10,4,7,2]
print(a6.sorted(by: >)) // [10, 7, 4, 2, 1]

可以加到数组扩展中,通过扩展约束能够指定特定元素类型的排序,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
extension Array where Element == Int {
// 升序
func intSortedASC() -> [Int] {
return self.sorted(by: <)
}
// 降序
func intSortedDESC() -> [Int] {
return self.sorted(by: <)
}
}

print(a6.intSortedASC()) // 使用扩展增加自定义排序能力

1.4 数组检索

在数组中检索满足条件的元素。

第一个满足条件了就返回:

1
2
3
4
5
// 
let a7 = a4.first {
$0.n == 10
}
print(a7?.n ?? 0)

是否都满足了条件:

1
2
print(a4.allSatisfy { $0.n == 1 }) // false
print(a4.allSatisfy(\.b)) // true

找出最大的那个:

1
2
3
4
print(a4.max(by: { e1, e2 in
e1.n < e2.n
}) ?? S1(n: 0))
// S1(n: 10, b: true)

看看是否包含某个元素:

1
2
3
4
print(a4.contains(where: {
$0.n == 7
}))
// false

1.5 切割数组

切片:

1
2
3
// 取前3个,并不是直接复制,对于大的数组有性能优势。
print(a6[..<3]) // [1, 10, 4] 需要做越界检查
print(a6.prefix(30)) // [1, 10, 4, 7, 2] 不需要做越界检查,也是切片,性能一样

去掉前3个:

1
print(a6.dropFirst(3)) // [7, 2]

prefix(while:)drop(while:) 方法,顺序遍历执行闭包里的逻辑判断,满足条件就返回,遇到不匹配就会停止遍历。prefix 返回满足条件的元素集合,drop 返回停止遍历之后那些元素集合:

1
2
3
4
5
6
7
8
9
let a8 = [8, 9, 20, 1, 35, 3]
let a9 = a8.prefix {
$0 < 30
}
print(a9) // [8, 9, 20, 1]
let a10 = a8.drop {
$0 < 30
}
print(a10) // [35, 3]

比 filter 更高效的删除元素的方法 removeAll

1
2
3
4
5
6
7
8
9
10
// 删除所有不满足条件的元素
var a11 = [1, 3, 5, 12, 25]
a11.removeAll { $0 < 10 }
print(a11) // [4, 3, 1, 3, 3] 随机

// 创建未初始化的数组
let a12 = (0...4).map { _ in
Int.random(in: 0...5)
}
print(a12) // [0, 3, 3, 2, 5] 随机

1.6 #if

#if 用于后缀表达式

1
2
3
4
5
6
7
let a13 = a11
#if os(iOS)
.count
#else
.reduce(0, +)
#endif
print(a13) //37

2.Sets Set<Int>

Set 是无序集合,元素唯一

2.1 常见方法

1
2
3
4
5
6
7
8
9
10
11
12
let s0: Set<Int> = [2, 4]
let s1: Set = [2, 10, 6, 4, 8]
let s2: Set = [7, 3, 5, 1, 9, 10]

let s3 = s1.union(s2) // 合集
let s4 = s1.intersection(s2) // 交集
let s5 = s1.subtracting(s2) // 非交集部分
let s6 = s1.symmetricDifference(s2) // 非交集的合集
print(s3) // [4, 2, 1, 7, 3, 10, 8, 9, 6, 5]
print(s4) // [10]
print(s5) // [8, 4, 2, 6]
print(s6) // [9, 1, 3, 4, 5, 2, 6, 8, 7]
1
2
3
4
// s0 是否被 s1 包含
print(s0.isSubset(of: s1)) // true
// s1 是否包含了 s0
print(s1.isSuperset(of: s0)) // true
1
2
3
let s7: Set = [3, 5]
// s0 和 s7 是否有交集
print(s0.isDisjoint(with: s7)) // true

2.2 可变 Set

1
2
3
4
var s8: Set = ["one", "two"]
s8.insert("three")
s8.remove("one")
print(s8) // ["two", "three"]

3.字典 [:]

字典是无序集合,键值对应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var d1 = [
"k1": "v1",
"k2": "v2"
]
d1["k3"] = "v3"
d1["k4"] = nil

print(d1) // ["k2": "v2", "k3": "v3", "k1": "v1"]

for (k, v) in d1 {
print("key is \(k), value is \(v)")
}
/*
key is k1, value is v1
key is k2, value is v2
key is k3, value is v3
*/
1
2
3
if d1.isEmpty == false {
print(d1.count) // 3
}

3.1 遍历value

1
2
3
4
5
// mapValues
let d2 = d1.mapValues {
$0 + "_new"
}
print(d2) // ["k2": "v2_new", "k3": "v3_new", "k1": "v1_new"]

3.2 对字典的值或键进行分组

1
2
3
4
5

let d3 = Dictionary(grouping: d1.values) {
$0.count
}
print(d3) // [2: ["v1", "v2", "v3"]]

3.3 字典取值

从字典中取值,如果键对应无值,则使用通过 default 指定的默认值

1
2
3
4
d1["k5", default: "whatever"] += "."
print(d1["k5"] ?? "") // whatever.
let v1 = d1["k3", default: "whatever"]
print(v1) // v3

3.4 compactMapValues

compactMapValues() 对字典值进行转换解包。可以解可选类型,并去掉 nil 值.

1
2
3
4
5
6
7
8
9
10
11
let d4 = [
"k1": 1,
"k2": 2,
"k3": nil
]
let d5 = d4.mapValues { $0 }
let d6 = d4.compactMapValues{ $0 }
print(d5)
// ["k3": nil, "k1": Optional(1), "k2": Optional(2)]
print(d6)
// ["k1": 1, "k2": 2]

参考资料:


Tips: Please indicate the source and original author when reprinting or quoting this article.