Swift 教程

什么是 Swift?

Swift 是苹果公司于 2014 年推出的现代编程语言,用于开发 iOS、macOS、watchOS 和 tvOS 应用。它结合了 C 和 Objective-C 的优点,同时引入现代语言的特性,语法简洁、安全、高效。

Swift 的核心特点

  • 安全:强类型系统、可选类型(Optional)、内存自动管理
  • 现代:函数式编程支持、泛型、协议导向编程
  • 快速:性能接近 C 语言,LLVM 编译优化
  • 简洁:语法直观,去掉了繁琐的指针操作
  • 开源:Swift 已在 GitHub 开源,支持 Linux 等平台

Swift 能做什么

  • iOS / iPadOS 应用开发
  • macOS 桌面应用开发
  • watchOS 手表应用
  • tvOS 电视应用
  • 服务端开发(使用 Vapor 等框架)

第一个 Swift 程序

print("Hello, Swift!")

// 在 Xcode Playground 或命令行直接运行
// swift hello.swift

开发环境

  • Xcode:macOS 上的官方 IDE
  • Swift Playgrounds:iPad/Mac 上的学习工具
  • 命令行:安装 Swift Toolchain 后用 swift 命令编译运行

本教程将从环境搭建开始,系统学习 Swift 的语法、面向对象、协议、泛型等核心知识。

Swift 环境搭建

Swift 环境搭建

根据平台不同,Swift 开发环境的搭建方式略有差异。

macOS(推荐)

1. 从 App Store 安装 Xcode(包含 Swift 编译器与 IDE)
2. 或只安装命令行工具:
   xcode-select --install
3. 验证:
   swift --version

Linux

# Ubuntu 示例
sudo apt-get install clang libicu-dev libcurl4-openssl-dev
wget https://download.swift.org/swift-5.10-release/.../swift-5.10-RELEASE-ubuntu22.04.tar.gz
tar -xzf swift-*.tar.gz
export PATH=$PATH:/path/to/swift/usr/bin
swift --version

Windows

1. 下载 Swift Toolchain 安装包
2. 同时安装 Visual Studio 2022 的 C++ 组件
3. 配置环境变量后:
   swift --version

创建第一个项目

# 命令行方式
mkdir HelloSwift && cd HelloSwift
cat > main.swift <<EOF
print("Hello, Swift!")
EOF
swift main.swift          # 直接运行
swiftc main.swift -o hello   # 编译成可执行文件
./hello

使用 Xcode 创建项目

1. 打开 Xcode → Create a new Xcode project
2. 选择 App(iOS)或 Command Line Tool(macOS)
3. 填写项目名称、组织标识
4. 选择 Swift 作为语言 → 创建
5. 点击运行按钮(Cmd+R)查看效果

常见问题

  • swift 命令找不到:检查 PATH 或 Xcode 组件安装
  • Xcode 版本过旧:Swift 版本过低,升级 Xcode
  • Linux 缺依赖:安装 clang 与 libicu 等库

Swift 基本语法

Swift 基本语法

Swift 语法简洁现代,本节省略地介绍最基础的元素。

注释

// 单行注释

/* 多行
   注释 */

/* 嵌套注释是允许的
   /* 内层注释 */
*/

分号

// 一行一条语句时,分号可省略
let a = 1
// 一行多条语句需要分号
let b = 2; print(b)

标识符

// 使用驼峰命名
let userName = "张三"
let maxScore = 100

// 可用中文等 Unicode 字符
let 年龄 = 28
print(年龄)

打印输出

print("Hello")
print("Hello", "World")              // 多参数空格分隔
print("Hello", terminator: "")       // 不换行
print("值: \(maxScore)")              // 字符串插值

代码块与分号结尾

if maxScore > 60 {
    print("及格")
} else {
    print("不及格")
}
// 无需分号结尾,{} 界定代码块

空白与换行

// Swift 对空白不敏感,但对换行敏感(语句以换行分隔)
let x = 1
let y = 2
let z = x +
        y      // 运算符开头可跨行

基本示例

let name = "老王"
var age = 30
age += 1
print("\(name) 今年 \(age) 岁")

Swift 数据类型

Swift 数据类型

Swift 是强类型语言,所有变量/常量都有明确的类型。

内置类型

Int          整数
Double       64 位浮点数
Float        32 位浮点数
Bool         布尔值(true/false)
String       字符串
Character    单个字符
Array        数组
Dictionary   字典
Set          集合
Optional     可选值

类型标注

let age: Int = 28
let price: Double = 99.5
let name: String = "Swift"
let isOK: Bool = true
let first: Character = "A"

类型推断

// 编译器根据赋值自动推断类型
let count = 10          // Int
let pi = 3.14           // Double
let greeting = "你好"    // String
let flag = false        // Bool

整数类型

Int8 / Int16 / Int32 / Int64  有符号
UInt8 / UInt16 / UInt32 / UInt64  无符号

let small: Int8 = 127       // Int8 范围 -128...127
let unsigned: UInt8 = 255   // UInt8 范围 0...255

浮点数

let d: Double = 3.14159265358979   // 64 位,精度高
let f: Float = 3.14                 // 32 位,精度低
// 整数与浮点运算需显式转换
let result = Double(10) + 3.5       // 13.5

类型转换

let intVal = 42
let doubleVal = Double(intVal)      // 42.0
let strVal = String(intVal)         // "42"
let backToInt = Int(doubleVal)      // 42

类型别名

typealias PhoneNumber = String
let myPhone: PhoneNumber = "13800000000"
print(myPhone)

检查类型

let value: Any = 100
if value is Int {
    print("是 Int 类型")
}

Swift 变量

Swift 变量

Swift 区分变量(var)与常量(let),这是语言安全设计的重要部分。

变量与常量

var score = 95          // 变量:可以修改
let maxScore = 100      // 常量:不可修改

score = 96              // 正确
// maxScore = 120       // 错误:常量不能修改

声明并指定类型

var name: String = "张三"
var age: Int = 28
var height: Double = 1.75
var isStudent: Bool = true

同时声明多个

var x = 0, y = 0, z = 0
var a: Int = 1, b: Int = 2

变量命名规则

// 1. 使用驼峰命名法
var userName = "李四"
// 2. 不能以数字开头
// 3. 可以使用 Unicode 字符(中文、emoji)
var 分数 = 99
var 😀 = "开心"
// 4. 避免与关键字冲突(如需要可用反引号)
var `class` = "班级"

print 输出

var message = "Hello"
print(message)
message = "World"
print(message)

// 字符串插值
var count = 10
print("数量: \(count) 个")

何时用 let / var

// 经验法则:能常量则常量
let pi = 3.14159          // 不变 → let
var counter = 0           // 需要变化 → var
counter += 1

变量作用域

let globalValue = 100     // 全局作用域

func test() {
    let localValue = 50   // 局部作用域,函数外不可访问
    print(globalValue)
    print(localValue)
}

Swift 可选类型

Swift 可选类型(Optional)

可选类型是 Swift 最重要的安全特性之一,用于表示"可能有值,也可能没有值(为 nil)"。

声明可选类型

// 类型后加 ? 表示可选
var name: String? = "张三"
var age: Int? = nil          // 可能无值
print(name)   // Optional("张三")
print(age)    // nil

强制解包

var name: String? = "老王"
// 使用 ! 强制解包(不安全,值为 nil 会崩溃)
print(name!)   // 老王

// 危险示例
var empty: String? = nil
// print(empty!)  // 崩溃:Fatal error

if 判断解包

var score: Int? = 85
if score != nil {
    print("分数: \(score!)")   // 已确认非空才用 !
}

可选绑定(if let)

var username: String? = "admin"

if let name = username {
    print("用户: \(name)")     // 自动解包,name 是 String
} else {
    print("用户名为空")
}

guard let

func checkUser(user: String?) {
    guard let u = user else {
        print("用户名为空,提前返回")
        return
    }
    // 这里 u 安全可用
    print("用户: \(u)")
}

隐式解包可选

// 类型后加 !,声明时确定必有值,使用时可省略 !
var assumedName: String! = "王五"
print(assumedName)   // 王五(不用写 !)

可选链

class Person {
    var residence: Residence?
}
class Residence {
    var rooms = 3
}

let p = Person()
// 可选链:只要链上有一个 nil,整体为 nil
let roomCount = p.residence?.rooms
print(roomCount)   // nil(不会崩溃)

nil 合并运算符

var input: String? = nil
let value = input ?? "默认值"    // ?? 提供默认值
print(value)   // 默认值

Swift 常量

Swift 常量

常量( let)声明后不可修改,是保证程序安全与可读性的重要机制。

声明常量

let maxAttempts = 5
let appName = "我的应用"
let pi = 3.14159

// 常量必须初始化
let answer: Int
answer = 42           // 之后一次性赋值(必须先声明未赋值)

常量不能修改

let speed = 100
// speed = 120   // 编译错误:let 常量不可修改

类型推断

let width = 100          // Int
let price = 19.9         // Double
let title = "教程"        // String

命名约定

let maxSpeed = 300       // 驼峰命名
let isEnabled = true     // 布尔用 is/has 前缀
// 全部大写的常量名不是 Swift 惯例(与其他语言不同)

let 与 var 的选择

// 值固定不变 → let
let gravity = 9.8
let daysInWeek = 7

// 值会变化 → var
var currentScore = 0
var playerHealth = 100

// 经验:尽量使用 let,让编译器帮你发现意外修改

常量与性能

// 编译器对 let 常量可以更好地优化
// 多线程环境下 let 常量天然线程安全
let sharedConfig = "prod"

结合可选类型

let optionalValue: Int? = 10
if let value = optionalValue {
    print(value)   // 10
}

Swift 字面量

Swift 字面量(Literals)

字面量是代码中直接书写的值,如数字、字符串、布尔等。

整数与浮点字面量

42          // 十进制
0b101010    // 二进制
0o52        // 八进制
0x2A        // 十六进制
1_000_000   // 下划线分隔(1,000,000)

3.14        // 浮点
1.5e2       // 科学计数法 = 150.0
0x1.0p2     // 十六进制浮点 = 4.0

字符串字面量

"Hello"     // 字符串
"""
多行字符串
可以换行
"""         // 多行字符串(三个引号)

特殊字符

"\n"   换行
"\t"   制表符
"\\"   反斜杠
"\""   双引号
"\u{1F600}"  Unicode 表情 😀

布尔字面量

true
false

nil 字面量

var value: Int? = nil   // nil 表示无值

数组字面量

let numbers = [1, 2, 3, 4]
let empty: [Int] = []

字典字面量

let person = ["name": "张三", "age": 28]
let empty: [String: Int] = [:]

类型标注字面量

let a: Int8 = 100
let b: UInt16 = 5000
let c: Float = 3.14
let d: Character = "A"

Swift 运算符

Swift 运算符

Swift 提供丰富的运算符,包括算术、比较、逻辑、位运算等。

算术运算符

let a = 10, b = 3
a + b    // 13
a - b    // 7
a * b    // 30
a / b    // 3(整数除法取整)
a % b    // 1(取余)
// 浮点取余
8.5.truncatingRemainder(dividingBy: 2.5)  // 1.0

赋值运算符

var x = 5
x += 3    // x = 8
x -= 2    // x = 6
x *= 2    // x = 12
x /= 3    // x = 4
x %= 3    // x = 1

比较运算符

==   等于     !=   不等于
>    大于     <    小于
>=   大于等于  <=   小于等于
// 比较结果都是 Bool
let isEqual = (10 == 10)    // true

三元运算符

let score = 85
let result = score >= 60 ? "及格" : "不及格"
print(result)   // 及格

逻辑运算符

&&   逻辑与
||   逻辑或
!    逻辑非

let age = 25
let ok = age > 18 && age < 60   // true
let any = age < 18 || age > 60  // false
let not = !(age > 18)           // false

区间运算符

1...5        // 闭区间:1,2,3,4,5
1..<5        // 半开区间:1,2,3,4
let names = ["A", "B", "C", "D"]
print(names[1...2])   // ["B", "C"]

// 单侧区间
for i in 1... {        // 无限(需 break)
    if i > 3 { break }
    print(i)
}

位运算符

let a: UInt8 = 0b1100
let b: UInt8 = 0b1010
a & b   // 0b1000 与
a | b   // 0b1110 或
a ^ b   // 0b0110 异或
~a      // 取反
a << 1  // 左移
a >> 1  // 右移

运算符优先级

// 乘除高于加减,可用括号明确
let result = 2 + 3 * 4        // 14
let result2 = (2 + 3) * 4     // 20

Swift 条件语句

Swift 条件语句

Swift 提供 if、if-else、guard、switch 等条件控制结构。

if 语句

let score = 85

if score >= 90 {
    print("优秀")
} else if score >= 60 {
    print("及格")
} else {
    print("不及格")
}

if 不带括号

// Swift 的 if 条件不需要括号,但{} 不可省略
let temperature = 30
if temperature > 28 {
    print("很热")
}

多条件组合

let age = 25
let hasID = true

if age >= 18 && hasID {
    print("允许进入")
}

if 与可选绑定

var username: String? = "admin"
if let name = username {
    print("欢迎, \(name)")
} else {
    print("未登录")
}

guard 提前返回

func process(score: Int?) {
    guard let s = score else {
        print("分数无效")
        return
    }
    // s 在这里安全可用
    if s >= 60 {
        print("及格: \(s)")
    } else {
        print("不及格: \(s)")
    }
}

switch 语句

let weekday = 3

switch weekday {
case 1:
    print("星期一")
case 2:
    print("星期二")
case 3...5:
    print("周中")
case 6, 7:
    print("周末")
default:
    print("无效")
}
// Swift 的 switch 不需要 break,每个 case 自动跳出

switch 匹配元组

let point = (1, 1)
switch point {
case (0, 0):
    print("原点")
case (_, 0):
    print("在 X 轴上")
case (0, _):
    print("在 Y 轴上")
case (-2...2, -2...2):
    print("在方框内")
default:
    print("在其他位置")
}

switch 绑定值

let value = (10, 20)
switch value {
case (let x, let y) where x > y:
    print("x 大于 y")
case (let x, let y):
    print("x = \(x), y = \(y)")
}

Swift 循环

Swift 循环

Swift 提供 for-in、while、repeat-while 三种循环结构。

for-in 循环

// 遍历区间
for i in 1...5 {
    print(i)        // 1 2 3 4 5
}

// 遍历数组
let names = ["张三", "李四", "王五"]
for name in names {
    print(name)
}

// 遍历字典
let dict = ["a": 1, "b": 2]
for (key, value) in dict {
    print("\(key): \(value)")
}

忽略循环值

// 用 _ 忽略不需要的值
for _ in 1...3 {
    print("执行三次")
}

stride 步进

// 从 0 到 10,步长 2
for i in stride(from: 0, through: 10, by: 2) {
    print(i)       // 0 2 4 6 8 10
}

// 不包含结束值
for i in stride(from: 0, to: 10, by: 2) {
    print(i)       // 0 2 4 6 8
}

while 循环

var count = 0
while count < 5 {
    print("count = \(count)")
    count += 1
}

repeat-while

var num = 10
repeat {
    print("num = \(num)")
    num -= 1
} while num > 5
// 至少执行一次

break 与 continue

// break:退出整个循环
for i in 1...10 {
    if i == 5 { break }
    print(i)       // 1 2 3 4
}

// continue:跳过本次迭代
for i in 1...10 {
    if i % 2 == 0 { continue }
    print(i)       // 1 3 5 7 9
}

循环标签

// 嵌套循环中跳出外层
outerLoop: for i in 1...3 {
    for j in 1...3 {
        if j == 2 { break outerLoop }
        print("\(i)-\(j)")
    }
}
// 输出:1-1

综合示例:九九乘法表

for i in 1...9 {
    var line = ""
    for j in 1...i {
        line += "\(j)×\(i)=\(i*j) "
    }
    print(line)
}

Swift 字符串

Swift 字符串

Swift 字符串是 Unicode 兼容的字符集合,使用 String 类型表示。

创建字符串

let str1 = "Hello"
let str2 = String("World")
let str3 = String(repeating: "ab", count: 3)   // "ababab"
let empty = String()                            // 空字符串
let empty2 = ""

字符串拼接

let a = "Hello"
let b = " World"
let c = a + b                 // "Hello World"
var d = a
d += b                        // "Hello World"

// 追加字符
var msg = "Hi"
msg.append("!")               // "Hi!"

字符串插值

let name = "老王"
let age = 30
let intro = "\(name) 今年 \(age) 岁"
print(intro)    // 老王 今年 30 岁

// 表达式插值
let sum = "3 + 5 = \(3 + 5)"   // "3 + 5 = 8"

多行字符串

let poem = """
床前明月光,
疑是地上霜。
"""
print(poem)

字符串常用属性

let text = "Hello Swift"
text.count                 // 11(字符数)
text.isEmpty               // false
text.hasPrefix("Hello")    // true
text.hasSuffix("Swift")    // true
text.uppercased()          // "HELLO SWIFT"
text.lowercased()          // "hello swift"

查找与替换

let s = "Hello, World"
s.contains("World")                    // true
s.contains("x")                        // false
s.replacingOccurrences(of: "World", with: "Swift")  // "Hello, Swift"
s.split(separator: ",")                // ["Hello", " World"]
s.firstIndex(of: ",")                  // Optional(5)

访问字符

let s = "Swift"
let start = s.startIndex
let second = s.index(start, offsetBy: 1)
print(s[second])        // "w"
// 遍历
for ch in s {
    print(ch)
}
// 取子串
let range = s.index(start, offsetBy: 1)..<s.index(start, offsetBy: 4)
print(s[range])         // "wif"

类型转换

let num = 42
let str = String(num)              // "42"
let back = Int(str)                // Optional(42)
let pi = 3.14
let piStr = String(format: "%.2f", pi)   // "3.14"

Swift 字符

Swift 字符(Character)

Character 表示单个字符,Swift 中的字符是 Unicode 标量,支持全球各种文字与 emoji。

字符字面量

let a: Character = "A"
let chinese: Character = "中"
let emoji: Character = "😀"

// 字符串包含一个字符时也可声明为 Character
let c: Character = "a"

遍历字符串字符

let word = "Swift"
for ch in word {
    print(ch)     // S w i f t
}

统计字符数

let text = "Hello"
print(text.count)    // 5

// Unicode 扩展字形簇算一个字符
let e1 = "é"         // 1 个字符
let e2 = "e\u{301}"  // 组合后仍是 1 个字符(é)
print(e1.count)      // 1
print(e2.count)      // 1

获取第一个/最后一个字符

let s = "Hello"
s.first        // Optional("H")
s.last         // Optional("o")
s.prefix(2)    // "He"(子序列)
s.suffix(2)    // "lo"

字符比较

let x: Character = "a"
let y: Character = "b"
print(x == y)        // false
print(x < y)         // true(按 Unicode 排序)

字符与字符串转换

let ch: Character = "X"
let str = String(ch)          // "X"
let s = "ABC"
let arr = Array(s)            // ["A", "B", "C"]
print(arr[0])                 // "A"

判断字符类型

let ch: Character = "5"
ch.isNumber          // true
ch.isLetter          // false
ch.isUppercase       // false
ch.isLowercase       // false

let letter: Character = "A"
letter.isLetter      // true
letter.isUppercase   // true
letter.isLowercase   // false

Swift 数组

Swift 数组(Array)

数组是存储有序、同类型元素的集合。

创建数组

let nums = [1, 2, 3, 4]              // 类型推断 [Int]
var empty: [Int] = []                // 空数组
var strings = [String]()             // 另一种空数组写法
var zeros = Array(repeating: 0, count: 5)   // [0,0,0,0,0]

访问元素

let fruits = ["苹果", "香蕉", "橙子"]
fruits[0]           // "苹果"
fruits[2]           // "橙子"
fruits.count        // 3
fruits.isEmpty      // false
fruits.first        // Optional("苹果")
fruits.last         // Optional("橙子")

添加与删除

var list = [1, 2, 3]
list.append(4)               // [1,2,3,4]
list.insert(0, at: 0)        // [0,1,2,3,4]
list += [5, 6]               // [0,1,2,3,4,5,6]
list.remove(at: 1)           // 移除第 2 个
list.removeLast()            // 移除末尾
list.removeAll()             // 清空

遍历

let arr = ["a", "b", "c"]
for item in arr {
    print(item)
}
// 带索引
for (index, item) in arr.enumerated() {
    print("\(index): \(item)")
}
// 下标遍历
for i in 0..<arr.count {
    print(arr[i])
}

切片

let arr = [1, 2, 3, 4, 5]
let slice = arr[1...3]      // ArraySlice [2,3,4]
let prefix3 = arr.prefix(3) // 前 3 个
let suffix2 = arr.suffix(2) // 后 2 个

查找

let nums = [5, 3, 8, 1, 9]
nums.contains(3)             // true
nums.firstIndex(of: 8)       // Optional(2)
nums.min()                   // Optional(1)
nums.max()                   // Optional(9)
nums.first { $0 > 5 }        // Optional(8)
nums.filter { $0 > 4 }       // [5, 8, 9]

排序

var nums = [3, 1, 2]
nums.sort()                  // 原地排序 [1,2,3]
let sorted = nums.sorted()   // 返回新数组
let desc = nums.sorted(by: >)   // 降序 [3,2,1]

map / filter / reduce

let nums = [1, 2, 3, 4]

// map:变换每个元素
let doubled = nums.map { $0 * 2 }        // [2,4,6,8]

// filter:过滤
let evens = nums.filter { $0 % 2 == 0 }  // [2,4]

// reduce:聚合
let sum = nums.reduce(0) { $0 + $1 }     // 10

Swift 字典

Swift 字典(Dictionary)

字典以键值对(Key-Value)存储数据,键唯一。

创建字典

let person = ["name": "张三", "age": "28"]
var empty: [String: Int] = [:]
var scores = [String: Int]()
var dict = Dictionary<String, Int>()

访问值

var scores = ["math": 90, "english": 85]
scores["math"]           // Optional(90)
scores["history"]        // nil(键不存在)
scores.count             // 2
scores.isEmpty           // false

添加与修改

var scores = ["math": 90]
scores["english"] = 85        // 添加
scores["math"] = 95           // 修改
scores.updateValue(100, forKey: "math")  // 返回旧值 Optional(95)
scores["physics"] = nil       // 移除键

删除

var scores = ["math": 90, "english": 85]
scores.removeValue(forKey: "math")    // 返回 Optional(90)
scores.removeAll()                     // 清空

遍历

let dict = ["a": 1, "b": 2, "c": 3]

// 遍历键值
for (key, value) in dict {
    print("\(key): \(value)")
}

// 只遍历键
for key in dict.keys {
    print(key)
}

// 只遍历值
for value in dict.values {
    print(value)
}

// 转数组
let keys = Array(dict.keys)
let values = Array(dict.values)

默认值访问

var counts = ["apple": 3]
// 不存在时返回默认值
let banana = counts["banana", default: 0]   // 0
// 递增技巧
counts["apple", default: 0] += 1            // apple: 4

字典与可选值

var config: [String: Any] = [
    "name": "app",
    "version": 1.2,
    "enabled": true
]

if let name = config["name"] as? String {
    print(name)    // "app"
}

合并字典

var d1 = ["a": 1, "b": 2]
let d2 = ["b": 20, "c": 30]
d1.merge(d2) { (_, new) in new }
// d1 = ["a":1, "b":20, "c":30]

Swift 函数

Swift 函数(Function)

函数是 Swift 代码组织的核心单元,支持参数标签、默认值、inout 等多种特性。

基础函数

func greet() {
    print("Hello!")
}
greet()   // 调用

// 带参数与返回值
func add(a: Int, b: Int) -> Int {
    return a + b
}
let sum = add(a: 3, b: 5)   // 8

参数标签

// 外部标签 from + 内部标签 name
func greet(from person: String) {
    print("你好, \(person)")
}
greet(from: "老王")

// 省略标签(_)
func multiply(_ a: Int, _ b: Int) -> Int {
    return a * b
}
multiply(3, 4)   // 12

默认参数

func sayHello(name: String, times: Int = 1) {
    for _ in 1...times {
        print("Hello, \(name)")
    }
}
sayHello(name: "Swift")          // 默认 1 次
sayHello(name: "Swift", times: 3)

可变参数

func sum(_ numbers: Int...) -> Int {
    return numbers.reduce(0, +)
}
sum(1, 2, 3)      // 6
sum(1, 2, 3, 4, 5) // 15

返回多个值(元组)

func stats(_ nums: [Int]) -> (min: Int, max: Int) {
    return (nums.min() ?? 0, nums.max() ?? 0)
}
let result = stats([3, 7, 1, 9])
print(result.min)   // 1
print(result.max)   // 9

inout 参数

// inout 允许修改传入的变量
func swapTwo('_ a: inout Int, _ b: inout Int) {
    let temp = a
    a = b
    b = temp
}
var x = 1, y = 2
swapTwo(&x, &y)
print(x, y)   // 2 1

函数作为参数

func applyTwice(_ fn: (Int) -> Int, to value: Int) -> Int {
    return fn(fn(value))
}
let result = applyTwice({ $0 * 2 }, to: 5)   // 20

函数类型与嵌套函数

// 函数类型
var operation: (Int, Int) -> Int = add

// 嵌套函数
func outer() -> () -> Void {
    func inner() {
        print("内部函数")
    }
    return inner
}
let fn = outer()
fn()

Swift 闭包

Swift 闭包(Closure)

闭包是自包含的函数代码块,可以捕获并存储其上下文中的变量和常量。

闭包语法

// 完整形式
let add: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in
    return a + b
}

// 简写:类型推断
let add2 = { (a: Int, b: Int) in a + b }

// 调用
print(add(1, 2))    // 3

尾随闭包

// 闭包作为最后一个参数时可写成尾随形式
let numbers = [3, 1, 2]
let sorted = numbers.sorted { $0 < $1 }   // 省略括号
// 等价于
let sorted2 = numbers.sorted(by: { $0 < $1 })

简写参数名

// $0, $1 表示第一、第二个参数
let nums = [1, 2, 3, 4, 5]
let doubled = nums.map { $0 * 2 }         // [2,4,6,8,10]
let evens = nums.filter { $0 % 2 == 0 }   // [2,4]
let sum = nums.reduce(0) { $0 + $1 }      // 15

捕获值

func makeIncrementer(amount: Int) -> () -> Int {
    var total = 0
    // 闭包捕获 total 变量
    return {
        total += amount
        return total
    }
}
let incrementByTen = makeIncrementer(amount: 10)
print(incrementByTen())   // 10
print(incrementByTen())   // 20

闭包作为参数

func perform(operation: () -> Void) {
    print("开始")
    operation()
    print("结束")
}

perform {
    print("执行任务")
}

@escaping 逃逸闭包

var handlers: [() -> Void] = []

func addHandler(_ handler: @escaping () -> Void) {
    // 闭包被保存起来,在函数返回后调用 → 需要 @escaping
    handlers.append(handler)
}

@autoclosure 自动闭包

func logIfTrue(_ condition: @autoclosure () -> Bool) {
    if condition() {
        print("条件为真")
    }
}
logIfTrue(5 > 3)   // 直接传表达式,自动包装为闭包

Swift 枚举

Swift 枚举(Enum)

Swift 枚举非常强大,支持关联值、原始值,是现代 Swift 编程的核心特性。

基础枚举

enum Direction {
    case north
    case south
    case east
    case west
}

// 或一行写法
enum Direction2 { case north, south, east, west }

let dir = Direction.north
// 类型已知时可省略枚举名
var dir2: Direction = .south

switch 匹配枚举

enum Compass {
    case north, south, east, west
}

func describe(_ d: Compass) {
    switch d {
    case .north: print("北")
    case .south: print("南")
    case .east:  print("东")
    case .west:  print("西")
    }
}
describe(.east)   // 东

原始值(Raw Value)

enum Grade: Int {
    case fail = 0
    case pass = 60
    case excellent = 90
}
print(Grade.pass.rawValue)        // 60
print(Grade(rawValue: 90)!)       // Optional(excellent)

// 字符串原始值
enum Status: String {
    case success = "SUCCESS"
    case error = "ERROR"
}
print(Status.success.rawValue)    // "SUCCESS"

关联值(Associated Values)

enum Result {
    case success(Int)
    case failure(String)
}

let r1 = Result.success(200)
let r2 = Result.failure("服务器错误")

switch r1 {
case .success(let code):
    print("成功, 状态码 \(code)")
case .failure(let msg):
    print("失败: \(msg)")
}

枚举方法

enum Weather {
    case sunny, rainy, cloudy

    // 枚举方法
    func advice() -> String {
        switch self {
        case .sunny: return "记得防晒"
        case .rainy: return "带伞"
        case .cloudy: return "天气舒适"
        }
    }
}
print(Weather.rainy.advice())   // 带伞

递归枚举

enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}

func evaluate(_ expr: ArithmeticExpression) -> Int {
    switch expr {
    case .number(let v):
        return v
    case .addition(let a, let b):
        return evaluate(a) + evaluate(b)
    case .multiplication(let a, let b):
        return evaluate(a) * evaluate(b)
    }
}

let expr = .addition(.number(2), .multiplication(.number(3), .number(4)))
print(evaluate(expr))   // 14

Swift 结构体

Swift 结构体(Struct)

结构体是值类型,Swift 中大量使用结构体(如 String、Array、Dictionary 都是结构体)。

定义结构体

struct Point {
    var x: Int
    var y: Int
}

// 自动获得成员构造器
let p = Point(x: 10, y: 20)
print(p.x, p.y)   // 10 20

值类型特性

// 结构体是值类型:赋值时复制
struct Rect {
    var width = 0
    var height = 0
}

var a = Rect(width: 10, height: 20)
var b = a          // 复制了一份
b.width = 100

print(a.width)     // 10(互不影响)
print(b.width)     // 100

方法

struct Calculator {
    var value = 0

    // 修改自身属性需要 mutating
    mutating func add(_ n: Int) {
        value += n
    }

    func current() -> Int {
        return value
    }
}

var calc = Calculator()
calc.add(5)
print(calc.current())   // 5

计算属性

struct Rectangle {
    var width = 0.0
    var height = 0.0

    // 计算属性:不存储,每次计算
    var area: Double {
        return width * height
    }
}

let rect = Rectangle(width: 5, height: 10)
print(rect.area)   // 50.0

属性观察器

struct Counter {
    var count = 0 {
        willSet {
            print("即将变为 \(newValue)")
        }
        didSet {
            print("之前是 \(oldValue)")
        }
    }
}

var c = Counter()
c.count = 5
// 即将变为 5
// 之前是 0

结构体 vs 类

特性结构体类
类型值类型引用类型
继承不支持支持
类型转换不支持支持
析构函数无有(deinit)
引用计数无有(ARC)

何时用结构体

// 苹果官方建议:默认使用结构体
// 满足以下条件时用结构体:
// 1. 封装少量简单数据
// 2. 赋值时希望复制而非共享
// 3. 不需要继承
// 4. 数据是值语义(如坐标、尺寸)

Swift 类

Swift 类(Class)

类是引用类型,支持继承、类型转换、析构等面向对象特性。

定义类

class Person {
    var name: String
    var age: Int

    // 构造器
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    func introduce() {
        print("我是 \(name),\(age) 岁")
    }
}

let p = Person(name: "张三", age: 28)
p.introduce()   // 我是 张三,28 岁

引用类型特性

class Car {
    var speed = 0
}

let car1 = Car()
let car2 = car1      // 引用同一实例(不复制)
car2.speed = 100

print(car1.speed)    // 100(共享修改)
print(car2.speed)    // 100

继承

class Animal {
    var name: String
    init(name: String) {
        self.name = name
    }
    func speak() {
        print("\(name) 发出声音")
    }
}

class Dog: Animal {
    var breed: String
    init(name: String, breed: String) {
        self.breed = breed
        super.init(name: name)
    }
    // 重写方法
    override func speak() {
        print("\(name)(\(breed)): 汪汪!")
    }
}

let dog = Dog(name: "旺财", breed: "金毛")
dog.speak()   // 旺财(金毛): 汪汪!

属性

class Account {
    // 存储属性
    var balance = 0.0
    // 计算属性
    var formatted: String {
        return String(format: "%.2f", balance)
    }
    // 只读计算属性
    var isOverdrawn: Bool { return balance < 0 }
}

懒加载

class DataLoader {
    // 首次访问时才创建
    lazy var data: [Int] = {
        print("加载数据...")
        return Array(1...1000)
    }()
}

析构函数

class FileHandler {
    init() {
        print("打开文件")
    }
    deinit {
        print("关闭文件")
    }
}

var handler: FileHandler? = FileHandler()
handler = nil   // 触发 deinit

类型属性与类型方法

class Config {
    // 类型属性(static)
    static let appName = "MyApp"
    // 类型方法
    static func version() -> String {
        return "1.0.0"
    }
}
print(Config.appName)       // MyApp
print(Config.version())     // 1.0.0

Swift 属性

Swift 属性(Properties)

属性分为存储属性、计算属性、类型属性三类,支持观察器与包装器。

存储属性

struct User {
    var name: String      // 变量存储属性
    let id: Int           // 常量存储属性
}

// 常量存储属性只能初始化一次
struct FixedLengthRange {
    var length: Int
    let maxLength: Int
}

计算属性

struct Circle {
    var radius: Double

    // 计算属性:get/set
    var area: Double {
        get {
            return Double.pi * radius * radius
        }
        set {
            radius = sqrt(newValue / Double.pi)
        }
    }

    // 只读计算属性(省略 get)
    var diameter: Double {
        radius * 2
    }
}

var circle = Circle(radius: 2)
print(circle.area)          // 12.566...
circle.area = 50
print(circle.radius)        // 3.989...

属性观察器

class StepCounter {
    var totalSteps = 0 {
        willSet {
            print("即将设置: \(newValue)")
        }
        didSet {
            print("从 \(oldValue) 变为 \(totalSteps)")
        }
    }
}

let counter = StepCounter()
counter.totalSteps = 100
// 即将设置: 100
// 从 0 变为 100

类型属性

struct SomeStruct {
    // 存储类型属性(必须默认值)
    static var storedTypeProp = "值"

    // 计算类型属性
    static var computedTypeProp: Int {
        return 42
    }
}

print(SomeStruct.storedTypeProp)   // 值
print(SomeStruct.computedTypeProp) // 42

属性包装器(Property Wrapper)

@propertyWrapper
struct Clamped<T: Comparable> {
    var value: T
    let min: T
    let max: T

    init(wrappedValue: T, min: T, max: T) {
        value = Swift.min(Swift.max(wrappedValue, min), max)
        self.min = min
        self.max = max
    }

    var wrappedValue: T {
        get { return value }
        set { value = Swift.min(Swift.max(newValue, min), max) }
    }
}

struct Temperature {
    @Clamped(min: 0, max: 100) var celsius = 50
}

var t = Temperature()
t.celsius = 150
print(t.celsius)   // 100(被限制在范围内)

全局与局部变量

// 全局变量(延迟初始化)
var globalCounter = 0

func test() {
    // 局部变量
    var local = 5
    local += 1
    print(local)
}

Swift 方法

Swift 方法(Methods)

方法是与类型关联的函数,分为实例方法与类型方法。

实例方法

class Counter {
    var count = 0

    // 实例方法
    func increment() {
        count += 1
    }

    func increment(by amount: Int) {
        count += amount
    }

    func reset() {
        count = 0
    }
}

let counter = Counter()
counter.increment()
counter.increment(by: 5)
print(counter.count)   // 6

self 关键字

struct Point {
    var x = 0.0
    var y = 0.0

    func isToTheRight(of other: Point) -> Bool {
        // self.x 明确表示实例属性
        return self.x > other.x
    }

    mutating func moveTo(x: Double, y: Double) {
        self.x = x
        self.y = y
    }
}

mutating 方法

// 结构体/枚举中修改自身需要 mutating
struct Stack {
    var items: [Int] = []

    mutating func push(_ item: Int) {
        items.append(item)
    }

    mutating func pop() -> Int? {
        return items.popLast()
    }
}

var stack = Stack()
stack.push(1)
stack.push(2)
print(stack.pop() ?? 0)   // 2

类型方法

struct Math {
    // static 类型方法
    static func square(_ n: Int) -> Int {
        return n * n
    }

    // class 类型方法(类中可被继承重写)
}

class Utility {
    class func hello() {
        print("Hello from Utility")
    }
}

print(Math.square(5))    // 25
Utility.hello()          // Hello from Utility

方法重写

class Vehicle {
    func makeSound() {
        print("嘟嘟")
    }
}

class Bicycle: Vehicle {
    override func makeSound() {
        print("叮铃铃")
    }
}

let b = Bicycle()
b.makeSound()   // 叮铃铃

方法参数中的 self

struct Person {
    var name: String

    // 方法内参数名与属性名相同时用 self 区分
    func rename(to name: String) {
        print("将 \(self.name) 改名为 \(name)")
    }
}

Swift 下标脚本

Swift 下标脚本(Subscripts)

下标脚本允许用 实例[索引] 语法访问集合元素,可以给类、结构体、枚举定义下标。

基础下标

struct TimesTable {
    let multiplier: Int

    // 定义下标
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}

let table = TimesTable(multiplier: 3)
print(table[6])    // 18

多维下标

struct Matrix {
    let rows: Int, columns: Int
    var grid: [Double]

    init(rows: Int, columns: Int) {
        self.rows = rows
        self.columns = columns
        grid = Array(repeating: 0.0, count: rows * columns)
    }

    // 两个参数的下标
    subscript(row: Int, column: Int) -> Double {
        get {
            return grid[(row * columns) + column]
        }
        set {
            grid[(row * columns) + column] = newValue
        }
    }
}

var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 9.5
print(matrix[0, 1])   // 9.5

读取与写入(get/set)

struct Counter {
    var count = 0

    // get-only 下标(只读)
    subscript(multiplier: Int) -> Int {
        return count * multiplier
    }
}

下标与类型推断

// 自定义类型的下标
struct User {
    var name: String
    var email: String

    subscript(key: String) -> String? {
        switch key {
        case "name": return name
        case "email": return email
        default: return nil
        }
    }
}

let user = User(name: "张三", email: "z@example.com")
print(user["name"] ?? "无")   // 张三
print(user["age"] ?? "无")    // 无

默认下标(数组/字典)

let arr = [10, 20, 30]
arr[0]          // 10(数组下标)

let dict = ["a": 1]
dict["a"]       // Optional(1)(字典下标)

注意事项

  • 下标参数数量不限,但每个参数必须有类型
  • 下标参数不能使用 inout
  • 下标可以重载(多个不同参数的下标)

Swift 继承

Swift 继承(Inheritance)

继承允许一个类获得另一个类的属性与方法,是面向对象的重要特性。

基础继承

class Vehicle {
    var currentSpeed = 0.0
    var description: String {
        return "速度 \(currentSpeed) km/h"
    }
    func makeNoise() {}
}

// 继承 Vehicle
class Car: Vehicle {
    var hasSunroof = false
}

let car = Car()
car.currentSpeed = 80
print(car.description)   // 速度 80.0 km/h

方法重写

class Bicycle: Vehicle {
    override func makeNoise() {
        print("叮铃铃!")
    }
}

let bike = Bicycle()
bike.makeNoise()   // 叮铃铃!

属性重写

class Train: Vehicle {
    // 重写存储属性的观察器
    override var currentSpeed: Double {
        didSet {
            print("速度更新为 \(currentSpeed)")
        }
    }
    // 重写计算属性
    override var description: String {
        return "火车,速度 \(super.currentSpeed) km/h"
    }
}

let train = Train()
train.currentSpeed = 120
print(train.description)

super 调用父类

class SmartCar: Car {
    override var description: String {
        // 调用父类实现
        return super.description + ", 智能汽车"
    }
}

防止重写(final)

class Fixed {
    // final 方法不能重写
    final func notOverridable() {}
}

// final 类不能继承
final class Sealed {
    // ...
}

继承与初始化

class Animal {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Dog: Animal {
    var breed: String
    init(name: String, breed: String) {
        self.breed = breed
        super.init(name: name)   // 先初始化自己的,再调父类
    }
}

let dog = Dog(name: "旺财", breed: "金毛")

类型检查与转换

let items: [Vehicle] = [Car(), Bicycle(), Vehicle()]

for item in items {
    if item is Car {                    // is 类型检查
        print("这是汽车")
    }
    if let car = item as? Car {        // as? 可选转换
        print("有天窗: \(car.hasSunroof)")
    }
}

Swift 构造过程

Swift 构造过程(Initialization)

构造器(Initializer)用于创建实例并初始化所有存储属性。

默认构造器

// 所有属性有默认值时,自动获得默认构造器
struct Point {
    var x = 0
    var y = 0
}
let p = Point()   // 默认构造器

// 结构体自动获得成员构造器
struct Size {
    var width: Double
    var height: Double
}
let s = Size(width: 10, height: 20)

自定义构造器

struct Temperature {
    var celsius: Double

    init(celsius: Double) {
        self.celsius = celsius
    }

    init(fahrenheit: Double) {
        self.celsius = (fahrenheit - 32) / 1.8
    }
}

let t1 = Temperature(celsius: 100)
let t2 = Temperature(fahrenheit: 212)
print(t2.celsius)   // 100.0

类构造器

class Person {
    var name: String
    var age: Int

    // 指定构造器
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    // 便利构造器(convenience)
    convenience init(name: String) {
        self.init(name: name, age: 0)
    }
}

let p1 = Person(name: "张三", age: 28)
let p2 = Person(name: "李四")   // 使用便利构造器

可选属性

class Survey {
    var question: String
    var answer: String?   // 可选属性自动初始化为 nil

    init(question: String) {
        self.question = question
    }
}

let survey = Survey(question: "你喜欢 Swift 吗?")
print(survey.answer)   // nil

常量属性

class Message {
    // 常量属性只能在初始化时赋值
    let sender: String

    init(sender: String) {
        self.sender = sender
    }
}

继承中的构造器

class Animal {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Dog: Animal {
    var breed: String

    // 自定义指定构造器
    init(name: String, breed: String) {
        self.breed = breed
        super.init(name: name)   // 必须先初始化自己的属性
    }

    // 重写父类构造器
    override init(name: String) {
        self.breed = "未知"
        super.init(name: name)
    }
}

可失败构造器

struct Animal2 {
    let species: String

    // 返回 Optional,失败时返回 nil
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

if let animal = Animal2(species: "猫") {
    print(animal.species)
}
let invalid = Animal2(species: "")   // nil

required 构造器

class Base {
    // 子类必须实现
    required init() {
        // ...
    }
}

class Child: Base {
    required init() {
        super.init()
    }
}

Swift 析构过程

Swift 析构过程(Deinitialization)

析构器(deinit)在实例释放前调用,用于清理资源,仅类支持。

基本析构器

class FileManager {
    let filename: String

    init(filename: String) {
        self.filename = filename
        print("打开文件: \(filename)")
    }

    deinit {
        print("关闭文件: \(filename)")
    }
}

// 使用
var manager: FileManager? = FileManager(filename: "data.txt")
manager = nil
// 输出:
// 打开文件: data.txt
// 关闭文件: data.txt

析构时机

// 1. 实例引用计数归零时
// 2. 超出作用域时(局部变量)
func test() {
    let local = FileManager(filename: "temp.txt")
    // 函数结束时 local 释放,deinit 调用
}
test()

// 3. 数组移除元素
var list: [FileManager?] = [FileManager(filename: "a.txt")]
list.removeAll()   // deinit 被调用

析构器与继承

class Base {
    deinit {
        print("Base deinit")
    }
}

class Sub: Base {
    deinit {
        print("Sub deinit")
    }
}

// 子类析构器先执行,然后父类
var obj: Sub? = Sub()
obj = nil
// Sub deinit
// Base deinit

析构器的限制

// 1. 每个类只能有一个 deinit
// 2. 不能手动调用(由系统自动调用)
// 3. 不能带参数
// 4. 不能在子类调用父类 deinit(自动执行)
// 5. 结构体不支持析构器

典型用途

class DatabaseConnection {
    init() {
        print("建立数据库连接")
    }
    deinit {
        print("断开数据库连接")   // 清理连接
    }
}

class TimerHandler {
    var timer: Timer?
    deinit {
        timer?.invalidate()      // 停止定时器
    }
}

Swift 可选链

Swift 可选链(Optional Chaining)

可选链允许在可能为 nil 的值上安全地访问属性、方法、下标,链上任意一环为 nil 则整体为 nil。

问题场景

class Person {
    var residence: Residence?
}
class Residence {
    var rooms = 3
}

let person = Person()
// 不安全方式:person.residence! 会崩溃(值为 nil)
// 可选链方式:
let count = person.residence?.rooms
print(count)   // nil(不会崩溃)

多层可选链

class Address {
    var street: String?
    var city: String?
}
class Residence {
    var address: Address?
}
class Person {
    var residence: Residence?
}

let person = Person()
// 多层链式访问
let city = person.residence?.address?.city
print(city)   // nil

// 赋值操作(链上有一环为 nil 则赋值失败,无副作用)
person.residence?.address?.city = "北京"
print(person.residence?.address?.city)   // nil

可选链调用方法

class Printer {
    func printMessage(_ msg: String) {
        print("打印: \(msg)")
    }
}

var printer: Printer? = Printer()
printer?.printMessage("Hello")   // 打印: Hello

printer = nil
printer?.printMessage("Hi")      // 不执行,不崩溃

可选链访问下标

var scores: [String: Int]? = ["math": 90]
let math = scores?["math"]    // Optional(90)

scores = nil
let history = scores?["history"]   // nil

可选链返回值

// 通过可选链调用的返回值总是 Optional
class Residence2 {
    var rooms: [String] = ["客厅", "卧室"]

    func roomCount() -> Int {
        return rooms.count
    }
}

var residence: Residence2? = Residence2()
let count: Int? = residence?.roomCount()   // Optional(2)
print(count ?? 0)   // 2

结合 guard/if let

class Person3 {
    var age: Int?
}

let p = Person3()
p.age = 30

// 安全解包
if let age = p.age {
    print("年龄: \(age)")
} else {
    print("年龄未知")
}

Swift 自动引用计数

Swift 自动引用计数(ARC)

ARC(Automatic Reference Counting)自动管理类实例的内存:实例被引用时计数 +1,引用消失时 -1,归零后释放。

ARC 基本机制

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) 已初始化")
    }
    deinit {
        print("\(name) 已释放")
    }
}

// 引用计数变化
var p1: Person? = Person(name: "张三")   // 计数 1
var p2 = p1                                // 计数 2
var p3 = p1                                // 计数 3

p1 = nil   // 计数 2
p2 = nil   // 计数 1
p3 = nil   // 计数 0 → 释放,deinit 调用

循环引用问题

class Apartment {
    let unit: String
    var tenant: Person?

    init(unit: String) {
        self.unit = unit
    }
    deinit { print("公寓 \(unit) 释放") }
}

class Person {
    let name: String
    var apartment: Apartment?

    init(name: String) {
        self.name = name
    }
    deinit { print("人 \(name) 释放") }
}

// 互相引用 → 循环引用,两者都无法释放!
var person: Person? = Person(name: "张三")
var apartment: Apartment? = Apartment(unit: "A101")

person?.apartment = apartment
apartment?.tenant = person

person = nil        // 不会释放!
apartment = nil     // 也不会释放!(内存泄漏)

weak 弱引用解决

// 一端用 weak(不增加引用计数,自动变 nil)
class Person2 {
    let name: String
    var apartment: Apartment2?
    init(name: String) { self.name = name }
    deinit { print("\(name) 释放") }
}

class Apartment2 {
    let unit: String
    weak var tenant: Person2?    // 弱引用!
    init(unit: String) { self.unit = unit }
    deinit { print("公寓 \(unit) 释放") }
}

var person: Person2? = Person2(name: "张三")
var apartment: Apartment2? = Apartment2(unit: "A101")
person?.apartment = apartment
apartment?.tenant = person

person = nil      // 计数归零 → 释放 ✓
print(apartment?.tenant)   // nil(自动置空)

unowned 无主引用

// unowned 也不增加计数,但访问已释放对象会崩溃
// 适用于"引用的对象生命周期与自身相同或更长"的场景
class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) { self.name = name }
    deinit { print("\(name) 释放") }
}

class CreditCard {
    let number: String
    unowned let customer: Customer   // 卡一定属于某个客户
    init(number: String, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("卡 \(number) 释放") }
}

闭包中的循环引用

class HTMLElement {
    let name: String
    let text: String?

    // 闭包捕获 self → 循环引用
    lazy var asHTML: () -> String = { [weak self] in
        guard let self = self else { return "" }
        return "<\(self.name)>\(self.text ?? "")</\(self.name)>"
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    deinit { print("\(name) 释放") }
}

总结

类型计数置 nil适用
strong+1手动默认
weak不加自动可能为 nil,可先释放
unowned不加不自动生命周期更长,永不为 nil

Swift 类型转换

Swift 类型转换(Type Casting)

类型转换用 is 检查类型,用 as 转换类型,常用于类层次结构。

类型检查(is)

class MediaItem {
    var name: String
    init(name: String) { self.name = name }
}
class Movie: MediaItem {
    var director: String
    init(name: String, director: String) {
        self.director = director
        super.init(name: name)
    }
}
class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
        self.artist = artist
        super.init(name: name)
    }
}

let library: [MediaItem] = [
    Movie(name: "流浪地球", director: "郭帆"),
    Song(name: "晴天", artist: "周杰伦"),
    Movie(name: "哪吒", director: "饺子")
]

for item in library {
    if item is Movie {
        print("电影: \(item.name)")
    } else if item is Song {
        print("歌曲: \(item.name)")
    }
}

类型转换(as?)

// as? 可选转换:成功返回 Optional,失败返回 nil
for item in library {
    if let movie = item as? Movie {
        print("导演: \(movie.director)")
    } else if let song = item as? Song {
        print("歌手: \(song.artist)")
    }
}

强制转换(as!)

// as! 强制转换:失败会崩溃,仅确定类型时使用
let firstItem = library[0]
let firstMovie = firstItem as! Movie
print(firstMovie.director)   // 郭帆

向上转换(as)

// 子类 → 父类(总是安全)
let movie = Movie(name: "影片", director: "导演")
let media: MediaItem = movie as MediaItem

// 字面量类型转换
let intVal = 42 as Double        // 42.0(数值类型)
let num = 5 as Any

Any 与 AnyObject

// Any:任何类型(包括函数)
var things: [Any] = []
things.append(0)
things.append("字符串")
things.append(3.14)
things.append({ print("闭包") })

for thing in things {
    switch thing {
    case let num as Int:
        print("整数: \(num)")
    case let str as String:
        print("字符串: \(str)")
    case let d as Double:
        print("浮点: \(d)")
    default:
        print("其他")
    }
}

// AnyObject:任意类实例
var objs: [AnyObject] = []

与类型相关的集合操作

// 用类型转换过滤
let movies = library.compactMap { $0 as? Movie }
print(movies.count)   // 2

Swift 扩展

Swift 扩展(Extension)

扩展可以为已有类型添加新功能(方法、计算属性、下标等),无需修改原代码。

扩展计算属性

// 给 Double 添加扩展
extension Double {
    var km: Double { return self * 1000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
}

let distance = 5.0.km
print(distance)   // 5000.0

let length = 25.0.cm
print(length)     // 0.25

扩展方法

extension Int {
    // 实例方法
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }

    // mutating 方法
    mutating func square() {
        self = self * self
    }
}

3.repetitions {
    print("Hello!")
}

var num = 5
num.square()
print(num)   // 25

扩展下标

extension Int {
    // 下标:获取数字的第 n 位
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex { decimalBase *= 10 }
        return (self / decimalBase) % 10
    }
}

print(123456[0])   // 6
print(123456[2])   // 4

扩展嵌套类型

extension Int {
    enum Kind {
        case negative, zero, positive
    }

    var kind: Kind {
        switch self {
        case 0: return .zero
        case let x where x > 0: return .positive
        default: return .negative
        }
    }
}

print(5.kind)       // positive
print((-3).kind)    // negative

扩展协议遵循

// 让类型通过扩展遵循协议
struct Point {
    var x: Int
    var y: Int
}

extension Point: Equatable {
    static func == (lhs: Point, rhs: Point) -> Bool {
        return lhs.x == rhs.x && lhs.y == rhs.y
    }
}

let p1 = Point(x: 1, y: 2)
let p2 = Point(x: 1, y: 2)
print(p1 == p2)   // true

扩展的注意事项

// 1. 扩展不能添加存储属性
// 2. 扩展不能覆盖已有成员
// 3. 可以添加:计算属性、方法、下标、构造器、协议遵循

综合示例:字符串工具

extension String {
    var isEmail: Bool {
        return contains("@") && contains(".")
    }

    func repeatStr(_ times: Int) -> String {
        return String(repeating: self, count: times)
    }
}

print("test@example.com".isEmail)   // true
print("ab".repeatStr(3))            // ababab

Swift 协议

Swift 协议(Protocol)

协议定义了一组方法、属性和其他要求的蓝图,Swift 是协议导向编程语言,协议是其核心。

定义与遵循协议

// 定义协议
protocol Describable {
    var description: String { get }
    func describe()
}

// 遵循协议
struct Car: Describable {
    var brand: String

    var description: String {
        return "汽车品牌: \(brand)"
    }

    func describe() {
        print(description)
    }
}

let car = Car(brand: "特斯拉")
car.describe()   // 汽车品牌: 特斯拉

属性要求

protocol FullName {
    var firstName: String { get set }   // 可读写
    var lastName: String { get }        // 只读
}

struct Person: FullName {
    var firstName: String
    var lastName: String
}

方法要求

protocol Drawable {
    func draw()
    mutating func reset()   // 修改自身需要 mutating
}

// 结构体遵循
struct Circle: Drawable {
    func draw() {
        print("画圆")
    }
    mutating func reset() {
        print("重置")
    }
}

协议继承

protocol Machine {
    func start()
}
protocol AutoPilot: Machine {   // 协议继承
    func navigate()
}

class Drone: AutoPilot {
    func start() { print("启动") }
    func navigate() { print("导航") }
}

协议组合

protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}

// 用 & 组合多个协议
func greet(person: Named & Aged) {
    print("你好, \(person.name),\(person.age) 岁")
}

struct User: Named, Aged {
    var name: String
    var age: Int
}

greet(person: User(name: "张三", age: 28))

协议作为类型

protocol Shape {
    func area() -> Double
}

struct Square: Shape {
    var side: Double
    func area() -> Double { return side * side }
}

struct CircleShape: Shape {
    var radius: Double
    func area() -> Double { return Double.pi * radius * radius }
}

// 协议类型数组
let shapes: [Shape] = [Square(side: 4), CircleShape(radius: 2)]
for shape in shapes {
    print(shape.area())
}

协议扩展(默认实现)

protocol Greetable {
    func greet()
}

// 协议扩展提供默认实现
extension Greetable {
    func greet() {
        print("Hello!")
    }
}

struct ChineseGreeter: Greetable {
    // 可以不实现,用默认实现
}

struct EnglishGreeter: Greetable {
    func greet() {
        print("Hello, World!")
    }
}

ChineseGreeter().greet()   // Hello!
EnglishGreeter().greet()   // Hello, World!

委托模式(Delegate)

protocol DataDelegate: AnyObject {
    func didLoadData()
}

class DataLoader {
    weak var delegate: DataDelegate?

    func load() {
        print("加载数据...")
        delegate?.didLoadData()
    }
}

class ViewController: DataDelegate {
    let loader = DataLoader()

    init() {
        loader.delegate = self
        loader.load()
    }

    func didLoadData() {
        print("数据加载完成,更新 UI")
    }
}

// let vc = ViewController()

Swift 泛型

Swift 泛型(Generics)

泛型允许编写适用于任意类型的灵活、可复用的函数和类型,是 Swift 标准库的基础。

泛型函数

// 不用泛型:每种类型写一遍
func swapTwoInts(_ a: inout Int, _ b: inout Int) {}
func swapTwoStrings(_ a: inout String, _ b: inout String) {}

// 用泛型:一个函数搞定所有类型
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 1, y = 2
swapTwoValues(&x, &y)
print(x, y)   // 2 1

var s1 = "A", s2 = "B"
swapTwoValues(&s1, &s2)
print(s1, s2)   // B A

泛型类型

// 泛型栈
struct Stack<Element> {
    var items: [Element] = []

    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -> Element? {
        return items.popLast()
    }
}

var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
print(intStack.pop() ?? 0)   // 2

var strStack = Stack<String>()
strStack.push("Hello")
print(strStack.pop() ?? "")   // Hello

泛型约束

// 约束 T 遵循 Equatable
func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int? {
    for (index, item) in array.enumerated() where item == value {
        return index
    }
    return nil
}

let nums = [1, 2, 3, 4]
print(findIndex(of: 3, in: nums) ?? -1)   // 2

关联类型

protocol Container {
    // 关联类型:协议中的泛型
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
}

struct IntBox: Container {
    var items: [Int] = []

    typealias Item = Int   // 明确关联类型

    mutating func append(_ item: Int) {
        items.append(item)
    }
    var count: Int {
        return items.count
    }
}

泛型 where 子句

func allMatch<T: Equatable>(_ arr1: [T], _ arr2: [T]) -> Bool {
    guard arr1.count == arr2.count else { return false }
    for (a, b) in zip(arr1, arr2) {
        if a != b { return false }
    }
    return true
}

print(allMatch([1, 2], [1, 2]))   // true
print(allMatch([1, 2], [1, 3]))   // false

泛型与协议结合

// 约束元素遵循协议
func describeAll<T: Describable2>(_ items: [T]) {
    for item in items {
        item.describe()
    }
}

protocol Describable2 {
    func describe()
}

struct Point2: Describable2 {
    func describe() {
        print("坐标点")
    }
}

describeAll([Point2(), Point2()])

Swift 访问控制

Swift 访问控制(Access Control)

访问控制限制代码的可见范围,帮助封装实现细节、保护内部数据。

五个访问级别

open      最开放:模块外可访问、可继承、可重写(仅类和方法)
public    模块外可访问,但不可继承/重写
internal  默认:仅当前模块内可访问
fileprivate  仅当前文件内可访问
private   仅当前声明作用域内可访问

示例

// 默认 internal(不写修饰符)
class DefaultClass {
    var name = "默认"
}

// public:外部模块可访问
public class PublicClass {
    public var name = "公开"
    internal var version = 1     // 内部可见
    private var secret = "秘密"   // 仅本类可见

    public func showSecret() -> String {
        return secret    // 类内可访问私有属性
    }
}

private 用法

struct BankAccount {
    private(set) var balance = 0.0    // 外部只读
    private var transactions: [Double] = []

    mutating func deposit(_ amount: Double) {
        balance += amount
        transactions.append(amount)
    }
}

var account = BankAccount()
account.deposit(100)
print(account.balance)   // 100.0(可读)
// account.balance = 500 // 错误:不可写

// transactions 外部完全不可见

fileprivate

// fileprivate:同一文件内可见
class Helper {
    fileprivate var secretHelper = "文件内可见"
}

// 同一个文件里可以访问
let helper = Helper()
print(helper.secretHelper)   // 文件内可见

Getter/Setter 访问级别

struct Person {
    // 属性整体 public,setter 私有
    public private(set) var age = 0

    mutating func birthday() {
        age += 1
    }
}

var p = Person()
p.birthday()
print(p.age)      // 1(可读)
// p.age = 10      // 错误:不可写

类型成员的默认级别

// 类型的访问级别限制其成员的默认级别
public class PublicType {
    // 默认 internal(不写时)
    var member = 1
    // 显式 public
    public var publicMember = 2
    // 显式 private
    private var privateMember = 3
}

协议访问控制

// 协议默认 public 要求
public protocol PublicProtocol {
    func method()   // 协议要求默认 public
}

// 私有协议
private protocol PrivateProtocol {
    func hidden()
}

模块与框架

// 开发框架时:
// open/public: 对外暴露的 API
// internal:    框架内部实现
// fileprivate/private: 最细节的实现

// 使用框架时:
// 只能访问 open/public 成员

实践建议

1. 默认用 internal,不需要显式写出
2. 只有对外 API 才用 public/open
3. 内部状态用 private(private(set) 暴露只读)
4. 能用 private 就不用 fileprivate
5. 保持"最小可见性"原则
第 1 / 33 节