Swift 是 Apple 于 2014 年推出的现代系统级编程语言,具备类型安全、内存安全、高性能三大核心特性。本章覆盖 iOS 开发必须掌握的 Swift 语言精髓。
1.1 类型系统与基础语法
值类型 vs 引用类型
Swift 最重要的设计哲学之一:优先使用值类型。
| 类别 | 代表 | 特点 |
|---|---|---|
| 值类型 | struct、enum、tuple | 赋值时深拷贝,栈上分配,线程安全 |
| 引用类型 | class、closure | 赋值时共享引用,堆上分配,需注意多线程 |
swift
// ✅ struct 是值类型 - iOS 中优先使用
struct Point {
var x: Double
var y: Double
// mutating:值类型中修改属性的方法需要标记
mutating func translate(dx: Double, dy: Double) {
x += dx
y += dy
}
}
var p1 = Point(x: 1.0, y: 2.0)
var p2 = p1 // 深拷贝,完全独立
p2.x = 100
print(p1.x) // 1.0 ------ p1 不受影响
// ✅ class 是引用类型 - 需要共享/多态时使用
class ViewModel {
var title = "默认标题"
}
let vm1 = ViewModel()
let vm2 = vm1 // 共享同一对象
vm2.title = "新标题"
print(vm1.title) // "新标题" ------ 已被修改
何时用 struct,何时用 class?
- SwiftUI 的 View / Model → struct
- 需要继承 / 引用语义 / 生命周期管理 → class
- ViewModel(@Observable)→ class
let 与 var
swift
let maxCount = 100 // 常量,不可修改
var currentCount = 0 // 变量,可修改
// struct 常量:属性也不可修改
let point = Point(x: 1, y: 2)
// point.x = 3 ❌ 编译错误
// class 常量:引用不可变,但属性可修改
let viewModel = ViewModel()
viewModel.title = "新标题" // ✅ 可以
类型推断
swift
let name = "Alice" // String
let age = 25 // Int
let price = 9.99 // Double
let isActive = true // Bool
let tags = ["swift", "ios"] // [String]
// 明确类型时
let score: Float = 98.5
let id: Int64 = 1_000_000_000
1.2 可选类型(Optional)
可选类型是 Swift 安全性的核心机制,强制开发者显式处理「值可能不存在」的情况。
swift
// 声明可选:在类型后加 ?
var username: String? = nil
var age: Int? = 30
// ❌ 强制解包(危险!nil 时崩溃)
let name = username! // 如果 username 是 nil,崩溃
// ✅ 方式1:if let(可选绑定)
if let name = username {
print("用户名:\(name)")
} else {
print("未登录")
}
// ✅ 方式2:guard let(提前退出,推荐用于函数内)
func processUser(username: String?) {
guard let username = username else {
print("username 不能为空")
return
}
// 此后 username 已解包,可以直接使用
print("处理用户:\(username)")
}
// ✅ 方式3:??(Nil 合并运算符)
let displayName = username ?? "匿名用户"
// ✅ 方式4:可选链(链式安全访问)
struct Address { var city: String }
struct User { var address: Address? }
let user: User? = User(address: Address(city: "上海"))
let city = user?.address?.city // String?,不会崩溃
print(city ?? "未知城市") // "上海"
1.3 函数与闭包
swift
// 基础函数
func greet(name: String, greeting: String = "你好") -> String {
return "\(greeting),\(name)!"
}
greet(name: "Alice") // "你好,Alice!"
greet(name: "Bob", greeting: "嗨") // "嗨,Bob!"
// 多返回值(元组)
func divideAndRemainder(_ a: Int, _ b: Int) -> (quotient: Int, remainder: Int) {
return (a / b, a % b)
}
let result = divideAndRemainder(17, 5)
print(result.quotient) // 3
print(result.remainder) // 2
// 可变参数
func sum(_ numbers: Int...) -> Int {
numbers.reduce(0, +)
}
sum(1, 2, 3, 4, 5) // 15
// inout - 引用传递(修改调用方的变量)
func double(_ value: inout Int) {
value *= 2
}
var number = 5
double(&number) // number 变为 10
// @discardableResult - 允许忽略返回值
@discardableResult
func saveData() -> Bool { true }
saveData() // 不用写 let _ = saveData()
闭包
swift
// 闭包是一等公民,可以赋值给变量、作为参数传递
let multiply: (Int, Int) -> Int = { a, b in a * b }
multiply(3, 4) // 12
// 尾随闭包语法
[1, 2, 3, 4, 5]
.filter { $0 % 2 == 0 } // [2, 4]
.map { $0 * $0 } // [4, 16]
.reduce(0, +) // 20
// 捕获列表(避免循环引用)
class ViewController {
var title = "主页"
func setupAction() {
// [weak self] 打破循环引用
let action = { [weak self] in
guard let self = self else { return }
print(self.title)
}
}
}
1.4 协议(Protocol)
协议是 Swift 面向协议编程(POP)的核心。
swift
// 定义协议(类似接口)
protocol Describable {
var description: String { get }
func describe() -> String
}
// 协议可选方法(通过 extension 提供默认实现)
extension Describable {
func describe() -> String {
return "这是一个:\(description)"
}
}
// 遵循协议
struct Article: Describable {
var title: String
var description: String { title }
}
let article = Article(title: "Swift 入门")
article.describe() // "这是一个:Swift 入门"
// 关联类型(泛型协议)
protocol Repository {
associatedtype Entity: Identifiable
func getAll() async throws -> [Entity]
func getById(_ id: Entity.ID) async throws -> Entity?
func save(_ entity: Entity) async throws
func delete(_ id: Entity.ID) async throws
}
// Equatable / Hashable / Identifiable
struct Product: Identifiable, Hashable, Codable {
let id: UUID
var name: String
var price: Double
var category: Category
enum Category: String, Codable, CaseIterable {
case electronics = "电子"
case clothing = "服装"
case food = "食品"
}
}
// 协议组合
typealias Model = Identifiable & Hashable & Codable
// 协议作为类型约束
func printAll<T: Describable & Identifiable>(_ items: [T]) {
items.forEach { print($0.describe()) }
}
1.5 泛型
swift
// 泛型函数
func swap<T>(_ a: inout T, _ b: inout T) {
let temp = a; a = b; b = temp
}
// 泛型类型
struct Stack<Element> {
private var items: [Element] = []
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element? {
items.popLast()
}
var top: Element? { items.last }
var isEmpty: Bool { items.isEmpty }
var count: Int { items.count }
}
// 使用
var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
intStack.pop() // 2
// 带约束的泛型
func largest<T: Comparable>(_ array: [T]) -> T? {
array.max()
}
largest([3, 1, 4, 1, 5, 9, 2, 6]) // 9
largest(["banana", "apple", "cherry"]) // "cherry"
// Result 类型(泛型枚举)
func divide(_ a: Double, _ b: Double) -> Result<Double, DivisionError> {
guard b != 0 else { return .failure(.divisionByZero) }
return .success(a / b)
}
switch divide(10, 3) {
case .success(let result): print("结果:\(result)")
case .failure(let error): print("错误:\(error)")
}
1.6 错误处理
swift
// 定义错误类型
enum NetworkError: Error, LocalizedError {
case invalidURL(String)
case noData
case decodingFailed(underlying: Error)
case serverError(code: Int, message: String)
case timeout
var errorDescription: String? {
switch self {
case .invalidURL(let url):
return "URL 格式无效:\(url)"
case .noData:
return "服务器未返回数据"
case .decodingFailed(let err):
return "数据解析失败:\(err.localizedDescription)"
case .serverError(let code, let msg):
return "服务器错误 \(code):\(msg)"
case .timeout:
return "请求超时,请检查网络连接"
}
}
}
// throw / try / catch
func fetchArticle(id: String) async throws -> Article {
guard !id.isEmpty else {
throw NetworkError.invalidURL("")
}
let url = URL(string: "https://api.example.com/articles/\(id)")!
let (data, response) = try await URLSession.shared.data(from: url)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw NetworkError.serverError(code: 500, message: "内部错误")
}
do {
return try JSONDecoder().decode(Article.self, from: data)
} catch {
throw NetworkError.decodingFailed(underlying: error)
}
}
// 调用处处理错误
Task {
do {
let article = try await fetchArticle(id: "123")
print("获取成功:\(article.title)")
} catch let error as NetworkError {
print(error.errorDescription ?? "未知错误")
} catch {
print("其他错误:\(error)")
}
}
// try? - 忽略错误,返回 Optional
let article = try? await fetchArticle(id: "123")
// try! - 强制(危险!只在确定不会失败时使用)
let url = try! URL(string: "https://apple.com")
1.7 属性与下标
swift
struct Circle {
var radius: Double
// 计算属性(没有存储,每次访问都计算)
var area: Double {
.pi * radius * radius
}
var diameter: Double {
get { radius * 2 }
set { radius = newValue / 2 }
}
// 属性观察器
var color: String = "红色" {
willSet { print("即将设置颜色为:\(newValue)") }
didSet { print("颜色已从 \(oldValue) 改为 \(color)") }
}
// 惰性属性(首次访问时才初始化,节省资源)
lazy var description: String = {
"一个半径为 \(radius) 的圆"
}()
}
// 属性包装器(@propertyWrapper)
@propertyWrapper
struct Clamped<T: Comparable> {
private var value: T
let range: ClosedRange<T>
var wrappedValue: T {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
init(wrappedValue: T, _ range: ClosedRange<T>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
}
struct Player {
@Clamped(0...100) var health: Int = 100
@Clamped(0...1) var volume: Double = 0.5
}
var player = Player()
player.health = 150 // 自动限制为 100
player.volume = -1 // 自动限制为 0
1.8 扩展(Extension)
swift
// 扩展原有类型,添加功能
extension String {
var isValidEmail: Bool {
let pattern = #"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"#
return range(of: pattern, options: .regularExpression) != nil
}
var trimmed: String { trimmingCharacters(in: .whitespacesAndNewlines) }
func repeated(_ times: Int) -> String {
String(repeating: self, count: times)
}
}
"alice@example.com".isValidEmail // true
" hello ".trimmed // "hello"
"iOS ".repeated(3) // "iOS iOS iOS "
// 扩展集合类型
extension Array where Element: Hashable {
var unique: [Element] {
var seen = Set<Element>()
return filter { seen.insert($0).inserted }
}
}
[1, 2, 2, 3, 3, 4].unique // [1, 2, 3, 4]
// 扩展实现协议
extension Int: Describable {
var description: String { "整数 \(self)" }
}
章节总结
| 知识点 | 核心要点 | 重要程度 |
|---|---|---|
| 值类型 vs 引用类型 | struct 优先,class 按需 | ⭐⭐⭐⭐⭐ |
| 可选类型 | guard let 提前退出 / ?? 默认值 | ⭐⭐⭐⭐⭐ |
| 闭包 | 尾随闭包 / [weak self] | ⭐⭐⭐⭐⭐ |
| 协议 + 扩展 | 面向协议编程 POP | ⭐⭐⭐⭐⭐ |
| 泛型 | 类型约束 / Result | ⭐⭐⭐⭐ |
| 错误处理 | throw/await throws/do-catch | ⭐⭐⭐⭐⭐ |
| 属性包装器 | @propertyWrapper | ⭐⭐⭐⭐ |
| 扩展 | 保持原类型整洁,分文件组织 | ⭐⭐⭐⭐ |
Demo 说明
本章 Demo 位于 iOS_demos/Chapter01_Swift语言/:
| 文件 | 演示内容 |
|---|---|
ValueReferenceDemo.swift |
值类型 vs 引用类型、COW 可视化 |
OptionalDemo.swift |
可选链、if let、guard let、?? |
ProtocolGenericsDemo.swift |
协议、泛型、扩展综合示例 |
ErrorHandlingDemo.swift |
错误定义、throw/catch、Result |
📎 扩展内容补充
来源:第一章_基础入门.md
本章概述:介绍 Swift 核心语言特性、Xcode 开发环境与项目结构、SwiftUI 与 UIKit 的架构对比,为后续章节奠定基础。
1.1 Swift 核心语言特性
概念讲解
Swift 是苹果于 2014 年推出的现代系统级编程语言,具备类型安全、内存安全、高性能三大核心特征。
值类型 vs 引用类型
Swift 中有一个核心区分:结构体(struct)/ 枚举(enum) 是值类型,类(class) 是引用类型。
swift
// 值类型 - 赋值时深拷贝
struct Point {
var x: Double
var y: Double
}
var p1 = Point(x: 1, y: 2)
var p2 = p1 // 深拷贝
p2.x = 100 // 不影响 p1
print(p1.x) // 输出: 1
// 引用类型 - 赋值时共享引用
class Person {
var name: String
init(name: String) { self.name = name }
}
let person1 = Person(name: "Alice")
let person2 = person1 // 共享引用
person2.name = "Bob"
print(person1.name) // 输出: "Bob"
项目中的应用:SwiftUI 的 View 和数据 Model 几乎都使用 struct,因为值类型天然线程安全且避免意外共享。
可选类型(Optional)
Swift 的核心安全机制,强制开发者处理 nil 情况。
swift
// 声明可选
var name: String? = nil
var age: Int? = 25
// 1. 可选绑定(推荐)
if let name = name {
print("姓名:\(name)")
} else {
print("姓名为空")
}
// 2. guard let(提前退出模式)
func greet(name: String?) {
guard let name = name else {
print("名字不能为空")
return
}
print("你好,\(name)!")
}
// 3. 可选链
struct User {
var address: Address?
}
struct Address {
var city: String
}
let user: User? = User(address: Address(city: "上海"))
print(user?.address?.city ?? "未知城市") // 输出: "上海"
// 4. Nil 合并运算符
let displayName = name ?? "匿名用户"
项目中的应用 :网络请求返回的数据字段通常是可选的,使用
guard let解包并提前返回是最常见的模式。
async/await 异步编程
Swift 5.5+ 引入的结构化并发,取代了回调地狱。
swift
// 定义异步函数
func fetchUserProfile(userId: String) async throws -> User {
let url = URL(string: "https://api.example.com/user/\(userId)")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
// 调用异步函数
Task {
do {
let user = try await fetchUserProfile(userId: "123")
print("用户名:\(user.name)")
} catch {
print("请求失败:\(error)")
}
}
// 并行执行多个异步任务
async let userTask = fetchUserProfile(userId: "123")
async let postsTask = fetchPosts(userId: "123")
let (user, posts) = try await (userTask, postsTask)
项目中的应用:所有网络请求、文件读写、数据库操作都使用 async/await,代码逻辑清晰,错误处理集中。
泛型与协议
swift
// 泛型函数
func swap<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
// 协议(类似 Flutter 的 Interface / Dart 的抽象类)
protocol Repository {
associatedtype Entity
func getAll() async throws -> [Entity]
func getById(_ id: String) async throws -> Entity?
func save(_ entity: Entity) async throws
func delete(_ id: String) async throws
}
// 协议扩展 - 提供默认实现
extension Repository {
func exists(_ id: String) async throws -> Bool {
return try await getById(id) != nil
}
}
// Equatable / Hashable / Identifiable
struct Product: Identifiable, Hashable {
let id: UUID = UUID()
var name: String
var price: Double
}
错误处理
swift
// 定义错误类型
enum NetworkError: Error, LocalizedError {
case invalidURL
case noData
case decodingFailed(String)
case serverError(Int)
var errorDescription: String? {
switch self {
case .invalidURL: return "URL 格式错误"
case .noData: return "无数据返回"
case .decodingFailed(let msg): return "解析失败:\(msg)"
case .serverError(let code): return "服务器错误:\(code)"
}
}
}
// Result 类型
func loadData() -> Result<Data, NetworkError> {
// ...
return .success(Data())
// 或 return .failure(.noData)
}
// 使用 Result
switch loadData() {
case .success(let data):
print("获取到 \(data.count) 字节")
case .failure(let error):
print(error.errorDescription ?? "未知错误")
}
1.2 Xcode 环境与项目结构
概念讲解
Xcode 功能区
┌─────────────────────────────────────────────────────┐
│ 工具栏(运行/停止/模拟器选择) │
├──────────┬──────────────────────────┬───────────────┤
│ 导航面板 │ 编辑区 │ 检查器面板 │
│ ・文件树 │ (代码 / 设计画布) │ ・属性设置 │
│ ・搜索 │ │ ・尺寸设置 │
│ ・问题 │ │ │
├──────────┴──────────────────────────┴───────────────┤
│ 调试面板(Console / Variables) │
└─────────────────────────────────────────────────────┘
SwiftUI 项目结构
MyApp/
├── MyApp.xcodeproj/ # Xcode 项目配置文件
│ └── project.pbxproj # 文件引用、编译配置
├── MyApp/
│ ├── MyAppApp.swift # App 入口(@main)
│ ├── ContentView.swift # 根视图
│ ├── Assets.xcassets/ # 图片资源、颜色、AppIcon
│ ├── Info.plist # App 配置(权限声明等)
│ ├── Preview Content/ # 预览专用资源
│ └── Models/ Views/ ... # 业务代码(自行组织)
└── MyAppTests/
└── MyAppTests.swift # 单元测试
Info.plist 常用配置
xml
<!-- 相机权限 -->
<key>NSCameraUsageDescription</key>
<string>需要访问相机进行拍照</string>
<!-- 定位权限 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要您的位置信息提供附近服务</string>
<!-- 网络安全(允许 HTTP)-->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
常用 Xcode 快捷键
| 快捷键 | 功能 |
|---|---|
⌘B |
编译 |
⌘R |
运行 |
⌘. |
停止 |
⌘⇧K |
清理构建 |
⌘⇧O |
快速打开文件 |
⌘⌃⇧P |
预览 Canvas |
⌥⌘/ |
生成文档注释 |
⌘⇧L |
添加 Library 组件 |
1.3 SwiftUI 架构原理
概念讲解
SwiftUI vs UIKit 对比
| 维度 | UIKit | SwiftUI |
|---|---|---|
| 编程范式 | 命令式 | 声明式 |
| 视图描述 | 代码创建并配置 | 描述「应该是什么样」 |
| 状态更新 | 手动调用更新方法 | 数据变化自动刷新 |
| 跨平台 | 仅 iOS/tvOS | iOS/macOS/tvOS/watchOS |
| 引入版本 | iOS 2.0 | iOS 13.0 |
| 成熟度 | 非常成熟 | 快速发展中 |
SwiftUI 视图树与渲染流程
数据变化(@State/@Observable)
↓
SwiftUI Diff(对比新旧 View 树)
↓
更新变化的视图(最小化更新)
↓
Layout(计算布局)
↓
Render(Metal 渲染)
App 入口结构
swift
// iOSDemosApp.swift - App 入口(类似 Flutter 的 main())
import SwiftUI
@main
struct iOSDemosApp: App {
// 全局状态可注入到环境
@StateObject private var appState = AppState()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(appState) // 注入全局状态
}
}
}
View 协议 - SwiftUI 的核心
swift
// SwiftUI 中每个 View 都是 struct
// 类似 Flutter 的 StatelessWidget
struct WelcomeView: View {
// 属性(类似 Flutter 的构造参数)
let username: String
// body 描述视图(类似 Flutter 的 build 方法)
var body: some View {
VStack(spacing: 20) {
Image(systemName: "star.fill")
.font(.largeTitle)
.foregroundStyle(.yellow)
Text("欢迎,\(username)!")
.font(.title)
.bold()
Text("开始你的 iOS 学习之旅")
.foregroundStyle(.secondary)
}
.padding()
}
}
// 预览(类似 Flutter 的热重载)
#Preview {
WelcomeView(username: "开发者")
}
三种视图类型对应关系
| Flutter | SwiftUI | 状态类型 |
|---|---|---|
| StatelessWidget | struct View(无状态) | 纯展示 |
| StatefulWidget + setState | View + @State | 局部状态 |
| ConsumerWidget (Riverpod) | View + @Observable | 外部状态 |
swift
// 1. 无状态视图(类比 StatelessWidget)
struct StaticCardView: View {
let title: String
let subtitle: String
var body: some View {
VStack(alignment: .leading) {
Text(title).font(.headline)
Text(subtitle).foregroundStyle(.secondary)
}
}
}
// 2. 有状态视图(类比 StatefulWidget)
struct CounterView: View {
@State private var count = 0 // 局部状态
var body: some View {
VStack {
Text("计数:\(count)")
.font(.largeTitle)
HStack {
Button("减少") { count -= 1 }
Button("增加") { count += 1 }
}
.buttonStyle(.borderedProminent)
}
}
}
// 3. 外部状态视图(类比 Consumer/ConsumerWidget)
@Observable
class AppViewModel {
var isLoggedIn = false
var currentUser: User?
}
struct ProfileView: View {
@Environment(AppViewModel.self) var viewModel
var body: some View {
if viewModel.isLoggedIn {
Text("欢迎,\(viewModel.currentUser?.name ?? "")")
} else {
Button("登录") { viewModel.isLoggedIn = true }
}
}
}
章节总结
| 知识点 | 核心要点 | 重要程度 |
|---|---|---|
| 值 vs 引用类型 | struct 是值类型、class 是引用类型 | ⭐⭐⭐⭐⭐ |
| Optional | 强制处理 nil,guard let 提前退出 | ⭐⭐⭐⭐⭐ |
| async/await | 结构化并发,替代回调 | ⭐⭐⭐⭐⭐ |
| 协议 + 扩展 | Swift 面向协议编程基础 | ⭐⭐⭐⭐ |
| 错误处理 | throw/catch/Result | ⭐⭐⭐⭐ |
| SwiftUI 架构 | 声明式 UI,数据驱动视图 | ⭐⭐⭐⭐⭐ |
Demo 说明
本章对应 Demo 位于 iOS_demos/Chapter01/:
| Demo 文件 | 演示内容 |
|---|---|
SwiftFeaturesDemo.swift |
Swift 核心语法交互演示 |
XcodeStructureDemo.swift |
项目结构可视化 |
SwiftUIArchitectureDemo.swift |
SwiftUI vs UIKit 架构对比 |