第一章:Swift 语言核心

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 架构对比
相关推荐
丿Wayne2 小时前
iOS Token 刷新实战(Actor 避免并发重复刷新)
ios·swift·token·actor·swift并发
终端安全笔记1 天前
iOS 27 给了租赁一个新工具,但它只认受监督的设备
android·网络·安全·ios
大熊猫侯佩1 天前
独立 App 首发完成 iPhone Duo 展开态适配
ios·swiftui·swift
光影少年1 天前
setImmediate 和 setTimeout(0) 的区别
android·前端·react.js·ios·前端框架
2501_916008891 天前
SSE 和 gRPC 流式接口如何抓包,调试 SSE 与 gRPC 流式接口
网络协议·计算机网络·网络安全·ios·adb·https·udp
HouWan2 天前
Flutter: MediaQuery.of(context) 为什么可能拖慢页面?
android·flutter·ios
SoaringHeart2 天前
Swift 进阶&封装:仿 Get 给SwiftUI 添加路由导航能力
swiftui·swift
用户38034165882972 天前
Broadcast Extension 里的 Live Activity:一次跨进程妥协
ios·音视频开发
匠测AI说2 天前
XCUITest 自动化全解:同进程白盒、XCTest 架构、自动同步机制与 iOS 端选型指南
测试工具·ios·自动化
silianpan2 天前
CAD 文档预览 UTS 插件
android·ios·harmonyos