第一章: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 架构对比
相关推荐
择势2 小时前
iOS RunLoop 原理深度解析与Swift高级用法
swift
90后的晨仔3 小时前
《SwiftUI 进阶第6章:列表与滚动视图》
ios
空中海4 小时前
第十章:iOS架构设计与工程化
macos·ios·cocoa
90后的晨仔11 小时前
《SwiftUI 进阶第7章:导航系统》
ios
90后的晨仔11 小时前
《swiftUI进阶 第9章SwiftUI 状态管理完全指南》
ios
90后的晨仔11 小时前
《 SwiftUI 进阶第8章:表单与设置界面》
ios
90后的晨仔11 小时前
《SwiftUI 进阶第5章:数据处理与网络请求》
ios
90后的晨仔12 小时前
《SwiftUI 进阶第4章:响应式布局》
ios
平淡风云12 小时前
IOS开发:如何获取苹果手机的uuid
ios·iphone·uuid