reference/docs/swift.md
Jovins 13991b8b5e
doc: update docs/swift.md (#558)
* fix issue

* add extension

* update
2024-03-06 17:36:48 +08:00

1800 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Swift 备忘清单
===
该备忘单提供了使用 [Swift](https://www.swift.org) 的示例,涵盖 Swift 基础知识、控制流、类型、结构/类、运算符、函数方法等。
入门
---
### 变量
<!--rehype:wrap-class=row-span-2-->
```swift
var score = 0 // 变量
let pi = 3.14 // 常数
var greeting = "Hello"
var numberOfToys = 8
var isMorning = true
var numberOfToys: Int = 8
numberOfToys += 1
print(numberOfToys) // 打印 "9"
```
### 类型注释
```swift
var greeting: String = "Hello"
var numberOfToys: Int = 8
var isMorning: Bool = true
var price: Double = 8.99
```
### 算术运算符
<!--rehype:wrap-class=row-span-3-->
- `+` 添加
- `-` 减法
- `*` 乘法
- `/` 分配
- `%` 余数
<!--rehype:className=cols-5 style-none-->
----
```swift
var x = 0
x = 4 + 2 // x 现在是 6
x = 4 - 2 // x 现在是 2
x = 4 * 2 // x 现在是 8
x = 4 / 2 // x 现在是 2
x = 4 % 2 // x 现在是 0
```
#### 复合赋值运算符
```swift
var numberOfDogs = 100
numberOfDogs += 1
print("有 \(numberOfDogs) 个斑点狗!")
// 打印: 有 101 个斑点狗!
```
----
- `+=` 添加和分配总和
- `-=` 减去并分配差值
- `*=` 乘并赋值
- `/=` 除并分配商
- `%=` 除并分配余数
<!--rehype:className=style-arrow cols-2-->
### 字符串插值
```swift
var apples = 6
print("I have \(apples) apples!")
// 打印: I have 6 apples!
```
### 多行字符串
```swift
let myLongString = """
Swift?
这是我最喜欢的语言!
"""
```
### 代码注释
```swift
// 这一行表示 Swift 中的注释。
/*
这都被注释掉了。
没有一个会跑!
*/
```
### 组成一个元组
<!--rehype:wrap-class=col-span-2-->
```swift
let player = ("Maya", 5, 150)
print(player) // ("Maya", 5, 150)
print("\(player.0): level \(player.1), \(player.2) pts") // Maya: level 5, 150 pts
```
### 分解元组
```swift
let player = (name: "Maya", level: 5)
let (currentName, curLevel) = player
print("\(currentName): level \(curLevel)")
// 打印: Maya: level 5
```
### 特殊注释语法 (MARK)
```swift
// MARK: - 查看设置
```
`MARK` 可用于在栏中显示评论
### 特殊注释语法 (TODO)
```swift
// TODO: 更新逻辑以适应数据更改
```
`TODO` 用于显示需要完成的事情的提醒
### 特殊注释语法 (FIXME)
```swift
// FIXME: 修复对现有条目进行更改时的故障行为
```
`FIXME` 用于显示需要修复的内容的提醒
变量
----
### 变量声明
变量用 `var` 声明:
```swift
var greeting = "你好"
var numberOfToys = 8
var isMorning = true
```
为了清楚起见,变量声明可以包含类型注释:
```swift
var greeting: String = "你好"
var numberOfToys: Int = 8
var isMorning: Bool = true
```
变量是可变的。 它们的值可以改变:
```swift
var numberOfToys: Int = 8
numberOfToys += 1
print(numberOfToys) // 打印“9”
```
### 常数
常量用 `let` 声明:
```swift
let greeting = "Hello"
let numberOfToys = 8
let isMorning = true
```
为清楚起见,常量声明可以包含类型注释:
```swift
let greeting: String = "Hello"
let numberOfToys: Int = 8
let isMorning: Bool = true
```
常量是不可变的。它们的值不能改变:
```swift
let numberOfToys: Int = 8
numberOfToys += 1
// ❌ 错误numberOfToys 不可变
```
### 计算变量get 和 set
<!--rehype:wrap-class=row-span-3-->
```swift
import Foundation
let df = DateFormatter()
df.dateFormat = "d MMMM yyyy"
var birth = df.date(from: "5 June 1999")!
var age: Int {
Calendar.current
.dateComponents([.year],
from: birth,
to: Date()).year!
}
print(age) // 20
birth = df.date(from: "5 June 2002")!
print(age) // 17
```
在下面的示例中distanceInFeet 有一个 `getter` 和一个 `setter`。 因为有 `setter`,所以 `getter` 需要关键字 `get`
```swift
var distanceInMeters: Float = 100
var distanceInFeet: Float {
get {
distanceInMeters * 3.28
}
set(newDistance) {
distanceInMeters = newDistance / 3.28
}
}
print(distanceInMeters) // 100.0
print(distanceInFeet) // 328.0
distanceInFeet = 250
print(distanceInMeters) // 76.21951
print(distanceInFeet) // 250.0
distanceInMeters = 800
print(distanceInMeters) // 800.0
print(distanceInFeet) // 2624.0
```
### willSet
<!--rehype:wrap-class=row-span-2-->
```swift
var distance = 5 {
willSet {
print("距离将被设置")
}
}
distance = 10 // 打印: 距离将被设置
```
可以在 `willSet` 中访问新值:
```swift
var distance = 5 {
willSet(newDistance) {
print("距离将被设置 \(newDistance)")
}
}
distance = 10 // 打印: 距离将被设置 10
```
`willSet` 可用于在设置变量值之前执行一些代码
### didSet
```swift
var distance = 5 {
didSet {
print("距离设置为 \(distance)")
print("它的旧值是: \(oldValue)")
}
}
distance = 10 // 打印: 距离将被设置 10
// 打印: 它的旧值是5
```
### willSet 和 didSet
```swift
var distance = 5 {
willSet(newDistance) {
print("距离将设置为 \(newDistance)")
}
didSet {
print("距离设置为 \(distance)")
print("它的旧值是: \(oldValue)")
}
}
distance = 10
```
条件和逻辑
---
### if 语句
```swift
var halloween = true
if halloween {
print("不给糖就捣蛋!")
}
// 打印: 不给糖就捣蛋!
if 5 > 3 {
print("5 大于 3")
} else {
print("5 不超过 3")
}
// 输出: "5 大于 3"
```
### else 语句
```swift
var turbulence = false
if turbulence {
print("请坐好。")
} else {
print("你可以自由地四处走动。")
}
// 打印: 你可以自由地四处走动。
```
### else if 语句
```swift
var weather = "rainy"
if weather == "sunny" {
print("拿点防晒霜")
} else if weather == "rainy" {
print("拿一把雨伞")
} else if weather == "snowing" {
print("穿上你的雪地靴")
} else {
print("无效天气")
}
// 打印: 拿一把雨伞
```
### 比较运算符
```swift
5 > 1 // true
6 < 10 // true
2 >= 3 // false
3 <= 5 // true
"A" == "a" // false
"B" != "b" // true
```
- `<` 小于
- `>` 大于
- `<=` 小于或等于
- `>=` 大于或等于
- `==` 等于
- `!=` 不等于
<!--rehype:className=style-round cols-2-->
### 三元条件运算符
```swift
var driverLicense = true
driverLicense
? print("驾驶座") : print("乘客座位")
// 打印: 驾驶座
```
### switch 语句
```swift
var secondaryColor = "green"
switch secondaryColor {
case "orange":
print("红色和黄色的混合")
case "purple":
print("红色和蓝色的混合")
case "green":
print("蓝色和黄色的混合")
default:
print("这可能不是辅助颜色")
}
// 打印: 蓝色和黄色的混合
```
### switch 语句:区间匹配
```swift
let year = 1905
var artPeriod: String
switch year {
case 1860...1885:
artPeriod = "印象派"
case 1886...1910:
artPeriod = "后印象派"
default:
artPeriod = "未知"
}
// 打印: 后印象派
```
### switch 语句:复合案例
```swift
let service = "Seamless"
switch service {
case "Uber", "Lyft":
print("旅行")
case "DoorDash", "Seamless", "GrubHub":
print("餐厅送餐")
case "Instacart", "FreshDirect":
print("杂货配送")
default:
print("未知服务")
}
// 打印: 餐厅外卖
```
### switch 语句where 子句
```swift
let num = 7
switch num {
case let x where x % 2 == 0:
print("\(num) 是偶数")
case let x where x % 2 == 1:
print("\(num) 奇数")
default:
print("\(num) 无效")
}
// 打印: 7 奇数
```
### 逻辑运算符
```swift
!true // false
!false // true
```
### 逻辑运算符 &&
```swift
true && true // true
true && false // false
false && true // false
false && false // false
```
### 逻辑运算符 ||
```swift
true || true // true
true || false // true
false || true // true
false || false // false
```
### 组合逻辑运算符
```swift
!false && true || false // true
```
`!false && true` 首先计算并返回 `true` 然后,表达式,`true` || `false` 评估并返回最终结果 `true`
```swift
false || true && false // false
```
`true && false` 首先计算返回 `false` 然后,表达式,`false` || `false` 评估并返回最终结果 `false`
### 控制执行顺序
```swift
// 没有括号:
true || true && false || false
// ----> true
// 带括号:
(true || true) && (false || false)
// ----> false
```
### 简单的 guard
```swift
func greet(name: String?) {
guard let unwrapped = name else {
print("Hello guest!")
return
}
print("Hello \(unwrapped)!")
}
greet(name: "Asma") // 输出Hello Asma!
greet(name: nil) // 输出Hello guest!
```
循环
----
### 范围
```swift
let zeroToThree = 0...3
// zeroToThree: 0, 1, 2, 3
```
### stride() 函数
```swift
for num in stride(from: 1, to: 5, by: 2) {
print(num)
}
// 打印: 1
// 打印: 3
```
### for-in 循环
```swift
for char in "hehe" {
print(char)
}
// 打印: h
// 打印: e
// 打印: h
// 打印: e
```
### continue 关键字
<!--rehype:wrap-class=row-span-2-->
```swift
for num in 0...5 {
if num % 2 == 0 {
continue
}
print(num)
}
// 打印: 1
// 打印: 3
// 打印: 5
```
`continue` 关键字将强制循环继续进行下一次迭代
### break 关键字
<!--rehype:wrap-class=row-span-2-->
```swift
for char in "supercalifragilistice" {
if char == "c" {
break
}
print(char)
}
// 打印: s
// 打印: u
// 打印: p
// 打印: e
// 打印: r
```
### 使用下划线
```swift
for _ in 1...3 {
print("Olé")
}
// 打印: Olé
// 打印: Olé
// 打印: Olé
```
### 遍历指定范围
```swift
for i in 0...10 {
print(i) //0 到 10
}
```
封闭指定范围操作符(...
### while 循环
```swift
var counter = 1
var stopNum = Int.random(in: 1...10)
// 循环打印,直到满足停止条件
while counter < stopNum {
print(counter)
counter += 1
}
```
`while` 循环接受一个条件,并在所提供的条件为 `true` 时持续执行其主体代码。如果条件从不为假,则循环将继续运行,程序将陷入`无限循环`
### repeate while
```swift
var counter = 1
repeat {
print(counter)
counter += 1
} while counter <= 5
```
至少执行一次
### 遍历字典对象
```swift
// 创建一个字典
var myDictionary = [
"name": "John", "age": 25
]
// 使用for-in循环遍历字典
for (key, value) in myDictionary {
print("\(key): \(value)")
}
```
数组和集合
----
### Array 数组
```swift
var scores = [Int]()
// 数组为空:[]
```
### .count 属性
```swift
var grocery = ["🥓", "🥞", "🍪", "🥛", "🍊"]
print(grocery.count)
// 打印: 5
```
### 索引
<!--rehype:wrap-class=row-span-2-->
索引是指项目在有序列表中的位置,使用下标语法 `array[index]` 从数组中检索单个元素。
```swift
var vowels = ["a", "e", "i", "o", "u"]
print(vowels[0]) // 打印: a
print(vowels[1]) // 打印: e
print(vowels[2]) // 打印: i
print(vowels[3]) // 打印: o
print(vowels[4]) // 打印: u
```
注意Swift 数组是零索引的,这意味着第一个元素的索引为 0。
### 用数组字面量初始化
```swift
// 使用类型推断:
var snowfall = [2.4, 3.6, 3.4, 1.8, 0.0]
// 明确类型:
var temp: [Int] = [33, 31, 30, 38, 44]
```
### .append() 方法和 += 运算符
```swift
var gymBadges = ["Boulder", "Cascade"]
gymBadges.append("Thunder")
gymBadges += ["Rainbow", "Soul"]
// ["Boulder", "Cascade", "Thunder",
// "Rainbow", "Soul"]
```
### .insert() 和 .remove() 方法
```swift
var moon = ["🌖", "🌗", "🌘", "🌑"]
moon.insert("🌕", at: 0)
// ["🌕", "🌖", "🌗", "🌘", "🌑"]
moon.remove(at: 4)
// ["🌕", "🌖", "🌗", "🌘"]
```
### 遍历数组
```swift
var employees = ["小王", "张三", "王五"]
for person in employees {
print(person)
}
// 打印: 小王
// 打印: 张三
// 打印: 王五
```
### 集合(Set)
```swift
var paintingsInMOMA: Set = [
"The Dream",
"The Starry Night",
"The False Mirror"
]
```
我们可以使用集合(`Set`)来存储相同数据类型的`唯一`元素
### 空集合(Set)
```swift
var team = Set<String>()
print(team)
// 打印: []
```
### 填充集合
```swift
var vowels: Set = ["a", "e", "i", "o","u"]
```
要创建一个填充有值的集合,请在赋值运算符之前使用 `Set` 关键字。
### .insert()
```swift
var cookieJar: Set = [
"Chocolate Chip",
"Oatmeal Raisin"
]
// 添加一个新元素
cookieJar.insert("Peanut Butter Chip")
```
### .remove() 和 .removeAll() 方法
```swift
var oddNumbers: Set = [1, 2, 3, 5]
// 移除现有元素
oddNumbers.remove(2)
// 删除所有元素
oddNumbers.removeAll()
```
### .contains() 检测数组中的值
```swift
var names: Set = ["Rosa", "Doug", "Waldo"]
print(names.contains("Lola")) //打印: false
if names.contains("Waldo"){
print("There's Waldo!")
} else {
print("Where's Waldo?")
}
// 打印: There's Waldo!
```
### 迭代一个集合
```swift
var recipe: Set = ["蛋", "面粉", "糖"]
for ingredient in recipe {
print ("在配方中包含\(ingredient)")
}
```
### .isEmpty 属性
```swift
var emptySet = Set<String>()
print(emptySet.isEmpty) // 打印: true
var populatedSet: Set = [1, 2, 3]
print(populatedSet.isEmpty) // 打印: false
```
### .count 属性
```swift
var band: Set = ["张三", "王五", "赵六"]
print("乐队有 \(band.count) 名演奏者。")
// 打印: 乐队有 4 名演奏者。
```
### .intersection() 交叉
```swift
var setA: Set = ["A", "B", "C", "D"]
var setB: Set = ["C", "D", "E", "F"]
var setC = setA.intersection(setB)
print(setC) // 打印: ["D", "C"]
```
### .union() 合并去重
```swift
var setA: Set = ["A", "B", "C", "D"]
var setB: Set = ["C", "D", "E", "F"]
var setC = setA.union(setB)
print(setC)
// 打印: ["B", "A", "D", "F", "C", "E"]
```
### .symmetricDifference() 对称差
```swift
var setA: Set = ["A", "B", "C", "D"]
var setB: Set = ["C", "D", "E", "F"]
var setC = setA.symmetricDifference(setB)
print(setC)
// 打印: ["B", "E", "F", "A"]
```
### .subtracting() 减法
```swift
var setA: Set = ["A", "B", "C", "D"]
var setB: Set = ["C", "D"]
var setC = setA.subtracting(setB)
print(setC)
// 打印: ["B", "A"]
```
字典
---
### 基础字典
```swift
var dictionaryName = [
"Key1": "Value1",
"Key2": "Value2",
"Key3": "Value3"
]
```
成对数据或键值对的`无序`集合
### Keys
```swift
var fruitStand = [
"Coconuts": 12,
"Pineapples": 12,
"Papaya": 12
]
```
每个`键`都是`唯一`的,即使它们都包含相同的`值`
### 类型一致性
```swift
var numberOfSides = [
"triangle": 3,
"square": 4,
"rectangle": 4
]
```
仅包含 `String` 键和 `Int`
### 初始化填充字典
```swift
var employeeID = [
"Hamlet": 1367,
"Horatio": 8261,
"Ophelia": 9318
]
```
### 初始化一个空字典
```swift
// 初始化器语法:
var yearlyFishPopulation = [Int: Int]()
// 空字典字面量语法:
var yearlyBirdPopulation: [Int: Int] = [:]
```
### 添加到字典
```swift
var pronunciation = [
"library": "lai·breh·ree",
"apple": "a·pl"
]
// 新键“programming”新值“prow·gra”
pronunciation["programming"] = "prow·gra"
```
### 删除键值对
<!--rehype:wrap-class=row-span-2-->
```swift
var bookShelf = [
"Goodnight": "Margaret Wise Brown",
"The BFG": "Roald Dahl",
"Falling Up": "Shel Silverstein",
"No, David!": "David Shannon"
]
// 通过将 key 设置为 nil 来删除值
bookShelf["The BFG"] = nil
// 使用 .removeValue() 删除值
bookShelf.removeValue(forKey: "Goodnight")
// 删除所有值
bookShelf.removeAll()
```
### 修改键值对
<!--rehype:wrap-class=row-span-2-->
```swift
var change = [
"Quarter": 0.29,
"Dime": 0.15,
"Nickel": 0.05
]
// 使用下标语法更改值
change["Quarter"] = .25
// 使用 .updateValue() 更改值
change.updateValue(.10, forKey: "Dime")
```
要更改键值对的值,请使用 `.updateValue()` 方法或下标语法,通过将括号 `[ ]` 和其中的现有键附加到字典的名称,然后添加赋值运算符 _(`=`)_ 后跟修改后的值
### .isEmpty 属性
```swift
var bakery = [String:Int]()
// 检查字典是否为空
print(bakery.isEmpty) // 打印 true
bakery["Cupcakes"] = 12
// 检查字典是否为空
print(bakery.isEmpty) // 打印 false
```
### .count 属性
```swift
var fruitStand = [
"Apples": 12,
"Oranges", 17
]
print(fruitStand.count) // 打印: 2
```
### 为变量赋值
```swift
var hex = [
"red": "#ff0000",
"yellow": "#ffff00",
"blue": "#0000ff",
]
print("蓝色十六进制代码 \(hex["blue"])")
// 打印: 蓝色十六进制代码 Optional("#0000ff")
if let redHex = hex["red"] {
print("红色的十六进制代码 \(redHex)")
}
// 打印: 红色的十六进制代码 #ff0000
```
将键值对的值分配给变量将返回一个可选值。要提取值,请使用可选的展开
### 遍历字典
```swift
var emojiMeaning = [
"🤔": "Thinking Face",
"😪": "Sleepy Face",
"😵": "Dizzy Face"
]
// 遍历键和值
for (emoji, meaning) in emojiMeaning {
print("\(emoji)被称为'\(meaning)Emoji'")
}
// 仅通过键迭代
for emoji in emojiMeaning.keys {
print(emoji)
}
// 仅通过值迭代
for meaning in emojiMeaning.values {
print(meaning)
}
```
函数
---
### 基础函数
```swift
func washCar() -> Void {
print("Soap")
print("Scrub")
print("Rinse")
print("Dry")
}
```
返回值为空的函数void
### 调用函数
```swift
func greetLearner() {
print("欢迎来到 Quick Reference!")
}
// 函数调用:
greetLearner()
// 打印: 欢迎来到 Quick Reference!
```
### 返回值
```swift
let birthYear = 1994
var currentYear = 2020
func findAge() -> Int {
return currentYear - birthYear
}
print(findAge()) // 打印: 26
```
### 多个参数
<!--rehype:wrap-class=col-span-2-->
```swift
func convertFracToDec(numerator: Double, denominator: Double) -> Double {
return numerator / denominator
}
let decimal = convertFracToDec(numerator: 1.0, denominator: 2.0)
print(decimal) // Prints: 0.5
```
### 省略参数标签
```swift
func findDiff(_ a: Int, b: Int) -> Int {
return a - b
}
print(findDiff(6, b: 4)) // 打印: 2
```
### 返回多个值
<!--rehype:wrap-class=col-span-2-->
```swift
func smartphoneModel() -> (name: String, version: String, yearReleased: Int) {
return ("iPhone", "8 Plus", 2017)
}
let phone = smartphoneModel()
print(phone.name) // 打印: iPhone
print(phone.version) // 打印: 8 Plus
print(phone.yearReleased) // 打印: 2017
```
### Parameters & Arguments
```swift
func findSquarePerimet(side: Int) -> Int {
return side * 4
}
let perimeter = findSquarePerimet(side: 5)
print(perimeter) // 打印: 20
// Parameter: side
// Argument: 5
```
### 隐式返回
```swift
func nextTotalSolarEclipse() -> String {
"April 8th, 2024 🌎"
}
print(nextTotalSolarEclipse())
// 打印: April 8th, 2024 🌎
```
### 默认参数
```swift
func greet(person: String = "guest") {
print("Hello \(person)")
}
greet() // Hello guest
greet(person: "Aliya") // Hello Aliya
```
### 输入输出参数
<!--rehype:wrap-class=row-span-2-->
```swift
var currentSeason = "冬天"
func season(month:Int, name:inout String) {
switch month {
case 1...2:
name = "冬天 ⛄️"
case 3...6:
name = "春天 🌱"
case 7...9:
name = "夏天 ⛱"
case 10...11:
name = "秋天 🍂"
default:
name = "未知"
}
}
season(monthNum: 4, name: &currentSeason)
print(currentSeason) // 春天 🌱
```
### 可变参数
```swift
func totalStudent(data: String...) -> Int {
let numStudents = data.count
return numStudents
}
print(totalStudent(data: "王五", "张三"))
// 打印: 2
```
### 可选参数
```swift
func getFirstInitial(from name: String?) -> String? {
return name?.first
}
```
<!--rehype:className=wrap-text-->
函数可以接受可选类型并返回可选类型。当一个函数不能返回请求类型的合理实例时,它应该返回 `nil`
### 省略 return 关键字
```swift
func multiply(x: Int, y: Int) -> Int {
x * y
}
```
### 额外指定参数命名标签
<!--rehype:wrap-class=row-span-2-->
```swift
func calculate(of numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
// 调用函数时,使用外部参数名
let result = calculate(of: 1, 2, 3, 4, 5)
print("Sum: \(result)")
```
### 函数作为参数
<!--rehype:wrap-class=row-span-2-->
```swift
func doMath(
operation: (Int, Int) -> Int,
a: Int, b: Int
) -> Int {
return operation(a, b)
}
// 定义一些可以作为参数传递的函数
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
// 使用 doMath 函数,并将 add 函数作为参数传递
let result = doMath(5, 3, operation: add)
print("Addition Result: \(result)")
```
### 闭包
```swift
let add: (Int, Int) -> Int = { (a, b) in
return a + b
}
// 调用闭包
let result = add(3, 5)
print("Sum: \(result)")
```
结构
----
### 结构创建
```swift
struct Building {
var address: String
var floors: Int
init(address: String, floors: Int) {
self.address = address
self.floors = floors
}
}
```
结构或结构用于以编程方式在代码中表示现实生活中的对象。结构是使用 `struct` 关键字创建的,后跟其名称,然后是包含其属性和方法的主体
### 默认属性值
```swift
struct Car {
var numOfWheels = 4
var topSpeed = 80
}
var reliantRobin = Car(numOfWheels: 3)
print(reliantRobin.numOfWheels) // 打印: 3
print(reliantRobin.topSpeed) // 打印: 80
```
### 结构实例创建
```swift
struct Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
// Person 实例:
var morty = Person(name: "张三", age: 14)
```
### init() 方法
<!--rehype:wrap-class=row-span-2-->
```swift
struct TV {
var size: Int
var type: String
init(size: Int, type: String) {
self.size = size
self.type = type
}
}
```
使用 `TV`
```swift
var newTV = TV(size: 65, type: "LED")
```
### 检查类型
```swift
print(type(of: "abc")) // 打印: String
print(type(of: 123)) // 打印: 123
```
### 变异方法(mutating)
<!--rehype:wrap-class=row-span-2-->
```swift
struct Menu {
var menuItems = ["Fries", "Burgers"]
mutating func addToMenu(dish: String) {
self.menuItems.append(dish)
}
}
```
使用 `Menu`
```swift
var dinerMenu = Menu()
dinerMenu.addToMenu(dish: "Toast")
print(dinerMenu.menuItems)
// 打印: ["Fries", "Burgers", "Toast"]
```
### 结构方法
```swift
struct Dog {
func bark() {
print("Woof")
}
}
let fido = Dog()
fido.bark() // 打印: Woof
```
Class
----
### 引用类型(类)
<!--rehype:wrap-class=row-span-2-->
```swift
class Player {
var name: String
init(name: String) {
self.name = name
}
}
var player1 = Player(name: "Tomoko")
var player2 = player1
player2.name = "Isabella"
print(player1.name) // Isabella
print(player2.name) // Isabella
```
### 类的实例
```swift
class Person {
var name = ""
var age = 0
}
var sonny = Person()
// sonny 现在是 Person 的一个实例
```
### init() 方法
<!--rehype:wrap-class=row-span-2-->
```swift
class Fruit {
var hasSeeds = true
var color: String
init(color: String) {
self.color = color
}
}
```
使用 Fruit 类
```swift
let apple = Fruit(color: "red")
```
可以使用 `init()` 方法和相应的初始化属性来初始化类,在 `init()` 方法中,`self` 关键字用于引用类分配属性值的实际实例
### 类属性
```swift
var ferris = Student()
ferris.name = "Ferris Bueller"
ferris.year = 12
ferris.gpa = 3.81
ferris.honors = false
```
### 继承
<!--rehype:wrap-class=row-span-2-->
假设我们有一个 BankAccount 类:
```swift
class BankAccount {
var balance = 0.0
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) {
balance -= amount
}
}
```
`SavingsAccount` 继承 `BankAccount`
```swift
class SavingsAccount: BankAccount {
var interest = 0.0
func addInterest() {
let interest = balance * 0.005
self.deposit(amount: interest)
}
}
```
新的 `SavingsAccount` 类(子类)自动获得了 `BankAccount` 类(超类)的所有特征。 此外,`SavingsAccount` 类定义了一个 `.interest` 属性和一个 `.addInterest()` 方法。
### 示例
使用数据类型
```swift
class Student {
var name: String
var year: Int
var gpa: Double
var honors: Bool
}
```
使用默认属性值
```swift
class Student {
var name = ""
var gpa = 0.0
var honors = false
}
```
### 这是结构定义和类定义的示例
```swift
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
```
`Resolution` 结构定义和 `VideoMode` 类定义仅描述 `Resolution``VideoMode` 的外观,创建结构或类的实例:
```swift
let resolution = Resolution(width: 1920)
let someVideoMode = VideoMode()
```
### 类的扩展
```swift
extension String {
var boolValue: Bool {
return self == "1"
}
}
let isTure = "0".boolValue
```
枚举
----
### 定义枚举
```swift
enum Day {
case monday
case tuesday
case wednesday
case thursday
case friday
case saturday
case sunday
}
let casualWorkday: Day = .friday
```
### Switch 语句
```swift
enum Dessert {
case cake(flavor: String)
case vanillaIceCream(scoops: Int)
case brownie
}
let custom: Dessert = .cake(flavor: "红色")
switch custom {
case let .cake(flavor):
print("你点了一个 \(flavor) 蛋糕")
case .brownie:
print("你点了一块巧克力蛋糕")
}
// 打印: "你点了一个红色天鹅绒蛋糕"
```
### CaseIterable
```swift
enum Season: CaseIterable {
case winter
case spring
case summer
case fall
}
for season in Season.allCases {
print(season)
}
```
添加对 `CaseIterable` 协议的一致性以访问 `allCases` 属性,该属性返回枚举的所有案例的数组
### 原始值
```swift
enum Beatle: String {
case john, paul, george, ringo
}
print("披头士是 \(Beatle.john.rawValue).")
// 打印: 披头士是 john.
```
### 相关值
```swift
enum Dessert {
case cake(flavor: String)
case vanillaIceCream(scoops: Int)
case brownie
}
let order: Dessert = .cake(flavor: "红色")
```
### 枚举的可赋值性
<!--rehype:wrap-class=row-span-2-->
```swift
enum Content {
case empty
case text(String)
case number(Int)
}
```
使用 switch 处理可赋值枚举
```swift
let content = Content.text("Hello")
switch content {
case .empty:
print("Value is empty")
case .text(let value):
print("Value is \(value)")
case .number(_): //不调用时,可以省略
print("Value is a number")
}
// 或者
if case .text(let value) = content {
print("Value is \(value)")
}
```
### 从原始值初始化
```swift
enum Hello: String {
case english = "Hello"
case japanese = "你好呀!"
case emoji = "👋"
}
let hello1 = Hello(rawValue: "你好呀!")
let hello2 = Hello(rawValue: "Привет")
print(hello1) // Optional(Hello.japanese)
print(hello2) // nil
```
### 计算属性
```swift
enum ShirtSize: String {
case small = "S"
case medium = "M"
case large = "L"
case extraLarge = "XL"
var description: String {
return "这件衬衫尺码是 \(self.rawValue)"
}
}
```
### 遍历字符串
```swift
enum Currency: String {
case euro = "EUR"
case dollar = "USD"
case pound = "GBP"
}
```
输出枚举的原始值
```swift
let euroSymbol = Currency.euro.rawValue
print("欧元的货币符号是 \(euroSymbol)")
```
### 实例方法
```swift
enum Traffic {
case light
case heavy
mutating func reportAccident() {
self = .heavy
}
}
```
枚举也可以有实例方法
```swift
var currentTraffic: Traffic = .light
currentTraffic.reportAccident()
// currentTraffic 现在是 .heavy
```
实例方法改变了枚举的值,则需要将其标记为 `mutating`
扩展
---
### 声明扩展
```swift
struct Person {
var name: String
var age: Int
func eat() {}
}
extension Person {
// 添加新功能
}
extension Person: SomeProtocol {
// 实现协议方法、属性
}
```
### 扩展构造器
<!--rehype:wrap-class=col-span-2-->
```swift
// 给CGRect结构体提供允许center和size的构造器
extension CGRect {
init(center: CGPoint, size: CGSize) {
let x: CGFloat = center.x - size.width * 0.5
let y: CGFloat = center.y - size.height * 0.5
self.init(origin: CGPoint(x: x, y: y),
size: size)
}
}
let frame = CGRect(center: CGPoint(x: 100, y: 100),
size: CGSize(width: 50, height: 50))
print("Origin is \(frame.origin)")
```
### 扩展可变实例方法
```swift
extension Double {
mutating func cube() {
self = self * self * self
}
}
var boxCube: Double = 2.0
boxCube.cube()
print(boxCube)
```
### 扩展方法
<!--rehype:wrap-class=col-span-2-->
```swift
extension String {
func deletingPrefix(_ prefix: String) -> String {
guard self.hasPrefix(prefix) else {
return self
}
return String(self.dropFirst(prefix.count))
}
}
print("Hello World".deletingPrefix("He"))
```
### 扩展计算属性
```swift
// 扩展可以添加计算属性,不能添加存储属性
extension Double {
var km: Double { self * 1000 }
var m: Double { self }
var cm: Double { self / 100.0 }
var mm: Double { self / 1000.0 }
}
let metric: Double = 30.48.cm
print("1 metric is \(metric.m) meter")
print("1 metric is \(metric.km) kilometer")
```
### 扩展存储属性
<!--rehype:wrap-class=col-span-2-->
```swift
// 但可以通过 objc_getAssociatedObject/objc_setAssociatedObject 实现添加存储属性
private var fuchsiaKey = "fuchsiaKey"
extension UIColor {
var fuchsia: UIColor? {
get {
return objc_getAssociatedObject(self, &fuchsiaKey) as? UIColor
}
set {
objc_setAssociatedObject(self, &fuchsiaKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
```
另见
----
- [Swift 文档(官方)](https://www.swift.org/documentation/) _(swift.or)_
- [快速编程语言(官方)](https://docs.swift.org/swift-book/) _(swift.or)_
- [Learn Swift](https://www.codecademy.com/resources/cheatsheets/language/swift) _(codecademy.com)_
- [Swift 开发人员的一站式快速参考](https://swiftly.dev/) _(swiftly.dev)_
- [Swift 入门教程、读书笔记](https://jaywcjlove.github.io/swift-tutorial) _(jaywcjlove.github.io)_