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. 保持"最小可见性"原则