Swift 基础知识(一)

一、Swift 中 类(class) 和 结构体(struct) 的区别,以及各自优缺点?

核心区别

特性 类(Class) 结构体(Struct)
类型 引用类型(传递时共享内存) 值类型(传递时复制新实例)
存储位置 堆内存 栈内存(若包含引用类型属性,其数据仍在堆内存)
继承 支持(除非用 final 修饰) 不支持
类型转换 支持运行时类型检查(is/as) 仅编译时类型检查
内存管理 引用计数(ARC) 自动栈内存释放(无需引用计数)
方法派发 动态派发(运行时确定方法地址) 静态派发(编译时确定方法地址)
析构函数 支持 deinit 不支持
线程安全 需手动处理(共享内存) 天然线程安全(值隔离)

赋值行为的本质

  • 类(浅拷贝)

    赋值时复制指针,新旧变量指向同一内存地址。修改任一变量会影响所有引用。

    swift 复制代码
    class Person {
        var name: String
        init(name: String) { self.name = name }
    }
    let p1 = Person(name: "Alice")
    let p2 = p1
    p2.name = "Bob"
    print(p1.name) // 输出 "Bob"
  • 结构体(深拷贝)

    赋值时复制值,新旧变量独立存储。修改一个不会影响另一个。

    swift 复制代码
    struct Point {
        var x: Int
        var y: Int
    }
    var p1 = Point(x: 1, y: 2)
    var p2 = p1
    p2.x = 3
    print(p1.x) // 输出 1

优缺点分析

类(Class)的优点
  1. 共享与可变状态:适合需要多个对象共享同一数据的场景(如网络请求管理器)。
  2. 继承与多态:支持面向对象设计,复用代码逻辑。
  3. 运行时动态性:支持类型检查、方法重写和 KVO。
类(Class)的缺点
  1. 内存开销:堆内存分配和引用计数管理增加性能损耗。
  2. 线程安全隐患:共享内存需额外同步机制(如锁、GCD)。
  3. 复杂性 :需处理循环引用(weak/unowned)。
结构体(Struct)的优点
  1. 高性能:栈内存分配速度快,无引用计数开销。
  2. 线程安全:值隔离特性天然避免共享内存冲突。
  3. 清晰所有权:深拷贝行为减少意外副作用。
结构体(Struct)的缺点
  1. 无法继承:不支持继承,复用代码需依赖协议和组合。
  2. 不适合复杂对象:频繁深拷贝大对象可能导致性能问题。

使用场景建议

场景 推荐类型 理由
轻量级数据模型(如坐标、颜色) 结构体 值类型更安全高效,无共享风险
需要继承或共享状态的组件 类 利用面向对象特性实现复用和动态行为
高频创建的临时对象 结构体 栈内存快速分配释放,减少堆内存压力
需线程安全的数据容器 结构体 值隔离避免竞态条件

补充说明

  1. 结构体中包含引用类型

    若结构体的属性是类实例,深拷贝时仅复制引用(指针),数据仍共享:

    swift 复制代码
    struct Container {
        var ref: NSMutableArray // 引用类型属性
    }
    var c1 = Container(ref: NSMutableArray())
    var c2 = c1
    c2.ref.add("Test") // c1.ref 也会被修改
  2. 协议与扩展

    结构体和类均可遵循协议并使用扩展,但结构体无法通过继承实现多态。

  3. Copy-on-Write 优化

    Swift 标准库中的集合类型(如 Array、Dictionary)对结构体实现了写时复制,避免不必要的深拷贝。


官方建议

Apple 在 Swift 官方文档 中明确推荐:

优先使用结构体,除非你需要类独有的特性(如继承、析构函数或引用语义)。

二、 Swift 中什么是可选类型?

1. 什么是可选类型?

可选类型(Optional)是 Swift 中一种特殊的数据类型,用于表示一个变量可能有值(如 Int、String 等),也可能没有值(nil)。它的核心设计目的是强制开发者显式处理值缺失的情况,从而避免空指针异常(Null Pointer Exception),提升代码的安全性。


2. 可选类型的语法

  • 声明可选类型 :在类型后添加 ?。

    swift 复制代码
    var name: String?  // 可能为 String 或 nil
    var age: Int?      // 可能为 Int 或 nil
  • 隐式解包可选类型 :在类型后添加 !。

    swift 复制代码
    var forcedValue: String!  // 声明时允许为 nil,但使用时假设已赋值

3. 可选类型的本质

可选类型是一个泛型枚举,定义如下:

swift 复制代码
public enum Optional<Wrapped> {
    case none       // 无值(nil)
    case some(Wrapped) // 有值(Wrapped 类型)
}

例如,String? 实际上是 Optional<String> 的简写。


4. 可选类型的解包方式

(1) 强制解包(Force Unwrap)

使用 ! 强制解包,但如果值为 nil 会触发运行时错误。

swift 复制代码
let name: String? = "Alice"
print(name!) // 输出 "Alice"

let age: Int? = nil
print(age!) // 运行时崩溃!
(2) 可选绑定(Optional Binding)

通过 if let 或 guard let 安全解包:

swift 复制代码
if let unwrappedName = name {
    print("Name is (unwrappedName)")
} else {
    print("Name is nil")
}
(3) 空合并运算符(Nil-Coalescing Operator)

提供默认值:

swift 复制代码
let name = optionalName ?? "Unknown"
(4) 可选链式调用(Optional Chaining)

安全访问属性或方法:

swift 复制代码
let length = user?.name?.count // 若任一环节为 nil,返回 nil

5. 隐式解包可选类型(Implicitly Unwrapped Optional)

  • 用途 :用于变量初始化后一定会被赋值,但声明时可能为 nil 的场景(如 IBOutlet)。
  • 风险 :若访问时仍为 nil,会触发运行时错误。
swift 复制代码
@IBOutlet weak var label: UILabel! // 隐式解包类型

6. 可选类型的优势

  • 安全性 :编译器强制处理 nil 情况,减少崩溃风险。
  • 清晰性:明确标记可能缺失的值,提升代码可读性。
  • 灵活性:与 Swift 的强类型系统结合,支持泛型和模式匹配。

7. 使用场景

  • 网络请求结果 :可能成功(有数据)或失败(nil)。

  • 用户输入处理:如文本框内容可能为空。

  • 类型转换 :尝试将 Any 转换为具体类型时可能失败。

    swift 复制代码
    let value: Any = "123"
    let number = value as? Int // Int?

8. 注意事项

  • 避免滥用 ! :强制解包应仅在确定值非 nil 时使用。
  • 优先使用可选绑定 :if let 和 guard let 更安全。
  • 合理使用隐式解包:仅用于生命周期明确的变量(如 UI 控件)。

9. 示例代码

swift 复制代码
// 定义一个可能为 nil 的可选类型
var optionalNumber: Int? = 42

// 安全解包
if let number = optionalNumber {
    print("The number is (number)")
} else {
    print("The number is nil")
}

// 空合并运算符
let validNumber = optionalNumber ?? 0

// 可选链式调用
struct Person {
    var address: Address?
}

struct Address {
    var street: String?
}

let person: Person? = Person(address: Address(street: "Main St"))
let street = person?.address?.street // 类型为 String?

10. 总结

可选类型是 Swift 语言的核心特性之一,通过编译时的严格检查,显著提升了代码的健壮性。合理使用可选类型及其解包方式,能有效避免空指针异常,同时使代码逻辑更加清晰可靠。

三、Swift 中什么 是 泛型?

泛型是 Swift 语言中的核心特性之一,允许开发者编写灵活、可重用且类型安全的代码。通过泛型,可以定义适用于多种数据类型的函数、类、结构体或枚举,而无需重复编写相同逻辑的代码。


1. 泛型的基本概念

泛型通过类型参数化 实现,类型参数在定义时作为占位符(如 <T>),在使用时由具体类型替换。例如:

swift 复制代码
// 泛型函数:交换任意类型的两个值
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 5, y = 10
swapTwoValues(&x, &y) // T 被推断为 Int

var str1 = "Hello", str2 = "World"
swapTwoValues(&str1, &str2) // T 被推断为 String

2. 泛型的核心作用

  • 代码复用:同一套逻辑可处理不同类型的数据。
  • 类型安全:编译器在编译时检查类型,避免运行时错误。
  • 性能优化:泛型在编译时生成具体类型的代码,无运行时开销。

3. 泛型的使用场景

(1) 泛型函数

适用于需要处理多种类型的算法(如排序、交换):

swift 复制代码
func findIndex<T: Equatable>(of value: T, in array: [T]) -> Int? {
    for (index, item) in array.enumerated() {
        if item == value { return index }
    }
    return nil
}

let names = ["Alice", "Bob"]
let index = findIndex(of: "Bob", in: names) // 返回 1
(2) 泛型类型

定义可存储任意类型数据的容器(如自定义集合):

swift 复制代码
struct Stack<Element> {
    private var elements = [Element]()
    mutating func push(_ element: Element) {
        elements.append(element)
    }
    mutating func pop() -> Element? {
        elements.popLast()
    }
}

var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)

var stringStack = Stack<String>()
stringStack.push("Swift")
(3) 泛型协议

通过 associatedtype 定义协议中的关联类型,允许遵循协议的类型自定义具体类型:

swift 复制代码
protocol Container {
    associatedtype Item
    var count: Int { get }
    mutating func append(_ item: Item)
    subscript(i: Int) -> Item { get }
}

struct IntList: Container {
    typealias Item = Int
    private var items = [Int]()
    var count: Int { items.count }
    mutating func append(_ item: Int) {
        items.append(item)
    }
    subscript(i: Int) -> Int { items[i] }
}

4. 泛型约束

限制泛型类型必须满足特定条件(如遵循协议、继承类或实现特定方法):

swift 复制代码
// 约束 T 必须遵循 Comparable 协议
func maxValue<T: Comparable>(_ a: T, _ b: T) -> T {
    return a > b ? a : b
}

// 约束 Key 必须遵循 Hashable,Value 可以是任意类型
struct Dictionary<Key: Hashable, Value> {
    private var storage = [Key: Value]()
    // ...
}

5. 关联类型(Associated Types)

在协议中使用关联类型,定义泛型需求:

swift 复制代码
protocol NetworkService {
    associatedtype Response: Decodable
    func fetchData(completion: @escaping (Result<Response, Error>) -> Void)
}

struct UserService: NetworkService {
    typealias Response = User // 指定具体类型
    func fetchData(completion: @escaping (Result<User, Error>) -> Void) {
        // 网络请求逻辑
    }
}

6. 类型擦除(Type Erasure)

处理需要隐藏具体泛型类型的场景(如返回泛型协议的实例):

swift 复制代码
struct AnyPrinter<T>: Printer {
    private let _print: (T) -> Void
    init<U: Printer>(_ printer: U) where U.T == T {
        _print = printer.print
    }
    func print(_ value: T) {
        _print(value)
    }
}

7. 泛型与标准库

Swift 标准库广泛使用泛型,例如:

  • 集合类型 :Array<Element>、Dictionary<Key, Value>。
  • 可选类型 :Optional<Wrapped>。
  • 错误处理 :Result<Success, Failure>。

8. 泛型的优势

  • 减少重复代码:无需为不同类型编写相同逻辑。
  • 增强类型安全:编译器在编译时检查类型错误。
  • 提升性能:无运行时类型转换开销。

9. 总结

场景 示例 核心作用
函数逻辑复用 swapTwoValues<T> 处理多种类型数据
自定义容器 Stack<Element> 存储任意类型元素
协议抽象 Container 协议 + 关联类型 定义灵活的类型需求
类型约束 T: Equatable 确保类型满足特定条件

通过合理使用泛型,开发者可以显著提升代码的灵活性和健壮性,同时减少冗余代码。


四、 Swift 中的 strong、weak 和 unowned 详解

1、基本概念

在 Swift 中,strong、weak 和 unowned 是用于管理对象引用计数的关键字,与 自动引用计数(ARC) 机制密切相关。它们的核心作用是 控制对象生命周期,避免内存泄漏或野指针问题。

关键字 行为 引用计数 是否可为 nil 安全性
strong 默认修饰符,持有对象时增加引用计数,对象不会被释放。 增加 否(非可选类型) 安全
weak 不增加引用计数,对象释放后自动置为 nil。 不增加 是(可选类型) 安全(自动置空)
unowned 不增加引用计数,对象释放后仍保留悬垂指针,访问时可能导致崩溃。 不增加 否(非可选类型) 不安全(需谨慎)

2、核心区别

(1). strong
  • 特点:默认修饰符,持有对象时会增加引用计数,对象生命周期由引用计数控制。

  • 适用场景:大多数情况下使用,表示明确的"拥有关系"。

  • 示例 :

    swift 复制代码
    class Person {
        var pet: Dog? // 默认是 strong
    }
(2). weak
  • 特点 :

    • 不增加引用计数,对象释放后自动置为 nil。
    • 必须声明为可选类型(var + ?)。
    • 它在对象释放后弱引用也随即消失。继续访问该对象,程序会得到 nil,不会出现崩溃。
  • 适用场景 :打破循环引用,尤其用于 非父子关系 的相互引用(如 delegate)。

  • 示例 :

    swift 复制代码
    class ViewController: UIViewController {
        weak var delegate: DataDelegate? // 弱引用避免循环
    }
(3). unowned
  • 特点 :

    • 不增加引用计数,但假设对象在生命周期内始终有效,不会为 nil。
    • 非可选类型,访问已释放的对象会导致崩溃。
  • 适用场景 :两个对象生命周期 严格同步,且被引用对象不会先于引用者释放。

  • 示例 :

    swift 复制代码
    class CreditCard {
        unowned let owner: Customer // Customer 一定比 CreditCard 生命周期长
        init(owner: Customer) {
            self.owner = owner
        }
    }

何时使用 unowned?

1. 适用场景
  • 对象生命周期严格绑定 :
    被引用对象(如 owner)的生命周期 长于或等于 引用者(如 CreditCard)。
  • 避免循环引用且无法使用 weak :
    当需要非可选类型且确保对象不会提前释放时。
2. 使用示例
swift 复制代码
class Customer {
    var card: CreditCard?
}

class CreditCard {
    unowned let owner: Customer
    init(owner: Customer) {
        self.owner = owner
    }
}

// 使用
let customer = Customer()
customer.card = CreditCard(owner: customer) // 无循环引用
3. 注意事项
  • 绝对不要滥用:必须确保被引用对象不会被提前释放。
  • 优先选择 weak :若无法确保生命周期同步,优先使用 weak。
  • unowned 与弱引用本质上一样。不同的是,unowned 无主引用 实例销毁后仍然存储着实例的内存地址(类似于OC中的unsafe_unretained), 试图在实例销毁后访问无主引用,会产生运行时错误(野指针)
  • weak unowned 只能用在 类实例上面
  • weak、unowned 都能解决 循环引用,unowned 要比 weak 性能 稍高
    • 在生命周期中可能会 变成 nil 的使用 weak
    • 初始化赋值以后再也不会变成 nil 使用 unowned

对比 weak 和 unowned

特性 weak unowned
是否可选 必须声明为可选类型(?) 非可选类型
安全性 自动置 nil,访问安全 可能触发野指针崩溃
生命周期假设 允许被引用对象提前释放 假设被引用对象始终存在
内存管理 无需手动置 nil 需确保引用对象生命周期

常见问题

1. 循环引用是如何产生的?

当两个对象通过 strong 相互引用时,引用计数无法归零,导致内存泄漏:

swift 复制代码
class A {
    var b: B?
}

class B {
    var a: A?
}

let a = A()
let b = B()
a.b = b // A 强引用 B
b.a = a // B 强引用 A → 循环引用!
2. 如何打破循环引用?
  • 将其中一个引用改为 weak 或 unowned:

    swift 复制代码
    class B {
        weak var a: A? // 弱引用打破循环
    }
3. 闭包中的循环引用

闭包捕获外部变量时默认是 strong,需使用捕获列表:

swift 复制代码
class NetworkManager {
    var completion: (() -> Void)?
    
    func fetchData() {
        // 使用 [weak self] 避免循环引用
        someAsyncTask { [weak self] in
            self?.handleData()
        }
    }
}

总结

场景 推荐修饰符 理由
默认对象引用 strong 明确所有权关系
打破父子对象外的循环引用 weak 安全自动置空
严格同步生命周期的对象引用 unowned 避免可选类型解包,需确保对象存活

通过合理使用 strong、weak 和 unowned,可以避免内存泄漏和野指针问题,写出更健壮的 Swift 代码。


五、Swift 中 static 与 class 关键字对比

核心区别

特性 static class
适用类型 class、struct、enum 仅 class
修饰存储属性 ✅ 允许 ❌ 禁止
修饰计算属性/方法 ✅ 允许 ✅ 允许
是否支持子类重写 ❌ 不可重写(隐含 final) ✅ 可重写(需用 override)
协议中的使用 协议中统一用 static,所有类型实现 协议中不可用,仅类实现时可选 class

使用场景

  1. static

    • 通用场景 :适用于所有类型(class、struct、enum)。
    • 存储属性:定义类级别的常量或变量。
    • 禁止重写:明确不希望子类重写的类型方法或属性。
    • 协议定义 :协议中声明类型方法或属性时,必须用 static。
  2. class

    • 类专用 :仅用于 class 类型。
    • 允许重写:希望子类重写父类的类型方法或计算属性。
    • 计算属性:定义可被子类重写的类计算属性。

示例代码

swift 复制代码
// 协议定义
protocol MyProtocol {
    static func protocolMethod()  // 协议中必须用 static
}

// 类实现
class Parent: MyProtocol {
    static var storageProperty = "Parent"  // 类存储属性
    class var computedProperty: String { "Parent" }  // 可重写的类计算属性
    class func classMethod() { }          // 可重写的类方法
    static func protocolMethod() { }      // 实现协议方法(隐含 final)
}

class Child: Parent {
    override class var computedProperty: String { "Child" }
    override class func classMethod() { }  // ✅ 允许重写
    // override static func protocolMethod() { }  // ❌ 禁止重写(static隐含final)
}

// 结构体实现
struct MyStruct: MyProtocol {
    static func protocolMethod() { }      // 结构体必须用 static
}

注意事项

  • 存储属性 :class 不能修饰存储属性(仅 static 可以)。
  • 协议兼容性 :协议中声明类型方法/属性时,使用 static;类实现时可用 class 或 static(static 会隐含 final)。
  • 性能优化 :static 方法/属性在编译期绑定,效率略高于 class。

六、Swift 访问控制总结

Swift 提供了 5 种访问控制级别,用于限制代码中实体(类、属性、方法等)的可见性,确保代码的封装性和安全性。以下是各访问级别的核心区别及使用场景:


1. 访问级别从高到低

关键字 作用范围 允许继承/重写 适用场景
open 跨模块可见,且允许其他模块继承或重写 ✅ 框架或库的公开 API(如 UIKit)
public 跨模块可见,但禁止其他模块继承或重写(类和成员默认不可继承) ❌ 暴露无需继承的工具类、方法
internal 仅当前模块内可见(默认级别) - 模块内部实现细节
fileprivate 仅当前文件内可见 - 文件内共享的辅助函数或类型
private 仅当前作用域(类型或扩展)内可见 - 类型内部的私有实现细节

2. 核心规则

  • 默认访问级别 :未显式指定时,默认为 internal。
  • 成员访问限制 :成员的访问级别不能高于其所属类型(如 public class 的 private 属性合法,但 private class 的 public 属性非法)。
  • 协议一致性 :遵循协议的类型必须满足协议要求的访问级别(如协议声明为 public,则遵循类型也需 public)。
  • 扩展中的访问控制 :扩展默认继承原始类型的访问级别,但可显式指定(如 private extension)。

3. 使用示例

框架开发(跨模块)
swift 复制代码
// Framework 模块
open class NetworkManager {        // 允许其他模块继承
    public static let shared = NetworkManager()
    internal func log() { }        // 仅模块内部可见
    private var token: String?     // 仅当前类可见
}

public struct APIError: Error {    // 其他模块可用,不可继承
    public let code: Int
}
模块内部
swift 复制代码
// App 模块
internal struct User {             // 默认 internal,仅模块内可见
    var name: String
    fileprivate var id: Int        // 同一文件内可见
}

private extension String {         // 扩展内所有成员默认 private
    func trimmed() -> String {
        self.trimmingCharacters(in: .whitespaces)
    }
}

4. 特殊场景

  • 单元测试 :通过 @testable import ModuleName 可访问模块的 internal 实体。
  • 子类重写 :子类方法的访问级别不能低于父类方法(如父类方法为 open,子类可重写为 public,但不能是 internal)。
  • 泛型约束:泛型类型的访问级别需与其类型参数一致或更高。

5. 选择指南

场景 推荐级别 示例
开发第三方框架或库 open/public 公开工具类、核心功能方法
模块内部工具类 internal 数据模型、网络请求封装
文件内共享的辅助函数 fileprivate 同一文件内的 JSON 解析工具
类型内部私有实现 private 缓存属性、敏感数据处理方法

通过合理使用访问控制,可以提升代码的可维护性,减少耦合,同时保护关键实现细节不被外部误用。

七、Swift 写时复制(Copy-on-Write)核心总结

1. 核心机制

  • 延迟复制 :值类型(如 Array、String)在赋值时不立即复制内存,而是共享同一份数据。
  • 写入触发:仅当修改副本时,才真正创建新内存,确保原数据不受影响。

2. 实现原理

  • 内部引用 :值类型内部通过引用类型(如类)存储实际数据。
  • 引用计数检查 :写入前调用 isKnownUniquelyReferenced,检测数据引用是否唯一:
    • 唯一引用:直接修改原数据。
    • 多引用:创建新副本后再修改,避免共享数据意外变更。

3. 优势

  • 性能优化:减少不必要的数据复制,提升内存效率。
  • 值类型安全:保留值语义(独立修改),同时兼顾性能。

4. 适用场景

  • 高频赋值的大数据:如集合操作、字符串处理。
  • 标准库类型 :Array、Dictionary、Set、String 默认支持 COW。

5. 示例

swift 复制代码
var a = [1, 2, 3]  // 内部引用计数为 1
var b = a           // 引用计数 +1(共享数据)
b.append(4)         // 检测到多引用,复制新内存再修改(a 仍为 [1,2,3])

总结

COW 通过共享数据 + 写入时复制,平衡了值类型的安全性与性能,是 Swift 高效处理大数据的核心机制。

八、Swift 将集合类型设计为值类型的原因

1. 值类型的核心优势

  • 线程安全 :值类型在传递时通过复制确保数据独立性,避免多线程同时修改同一内存。
  • 无副作用:方法调用不会意外修改原始数据,代码行为更易推理。
  • 内存高效 :结合 写时复制(Copy-on-Write, COW),减少不必要的内存分配。

2. 具体设计动机

(1) 安全性优先
  • 避免隐式共享 :引用类型多个变量指向同一内存,修改一处会影响所有引用(如 NSMutableArray)。

  • 值类型赋值即复制 :每个变量持有独立数据,修改副本不影响原数据。

    swift 复制代码
    var a = [1, 2, 3]
    var b = a
    b.append(4)
    print(a) // [1, 2, 3](a 未被修改)
(2) 性能优化
  • 栈内存分配:值类型默认在栈上分配,操作高效(指针移动即可)。

  • 写时复制(COW) :延迟实际内存复制,仅在修改时创建新副本。

    swift 复制代码
    var largeArray = [Int](repeating: 0, count: 1000000)
    var copy = largeArray // 不立即复制内存(共享存储)
    copy[0] = 1          // 修改时触发复制(独立存储)
(3) 不可变性的真正保证
  • let 语义严格 :值类型声明为 let 后,内容完全不可变。

  • 引用类型的缺陷 :即使使用 let 修饰引用类型(如 NSArray),内部数据仍可能被修改。

    swift 复制代码
    let nsArray: NSArray = NSMutableArray()
    let swiftArray = [1, 2, 3]
    // nsArray 可被其他引用修改(不安全),swiftArray 完全不可变

3. 与引用类型的对比

特性 值类型(Array/String/Dictionary) 引用类型(NSArray/NSString)
内存分配 栈 + COW 优化堆内存 堆内存
线程安全 天然安全(独立内存) 需手动同步(如锁、GCD)
赋值行为 深拷贝(COW 延迟实际复制) 浅拷贝(共享内存)
不可变性 let 完全不可变 let 仅保证引用不变,内容可能被其他引用修改

4. 写时复制(COW)的实现原理

  1. 内部引用类型存储 :值类型内部使用类(如 _ContiguousArrayStorage)存储实际数据。

  2. 引用计数检测 :通过 isKnownUniquelyReferenced 检查数据是否被多引用。

  3. 按需复制 :修改数据时,若引用非唯一,则创建新副本再修改。

    swift 复制代码
    struct MyArray<T> {
        private var storage: Storage<T> // 内部引用类型
        mutating func append(_ element: T) {
            if !isKnownUniquelyReferenced(&storage) {
                storage = storage.copy()
            }
            storage.append(element)
        }
    }

5. 总结

  • 安全第一:值类型 + COW 解决了引用类型在多线程和共享数据中的安全隐患。
  • 性能平衡:栈内存和 COW 机制将复制开销降至最低。
  • 开发友好:严格的不可变性和可预测行为,减少代码副作用。

通过将 Array、String、Dictionary 设计为值类型,Swift 在内存效率、线程安全和代码可靠性之间取得了最佳平衡,同时借助 COW 技术避免了传统值类型的性能缺陷。

相关推荐
茶底世界之下4 小时前
导出进度不是一个百分比:AVFoundation 收尾阶段的状态建模
ios·swift
大熊猫侯佩4 小时前
macOS27 上可变界面尺寸 iOS App 揭秘
macos·ios·swiftui
用户2181697049305 小时前
LLVM
ios
zeqinjie5 小时前
Flutter 获取 iPhone Duo 预留区位置
前端·flutter·ios
二流小码农5 小时前
鸿蒙开发:ArrayList,可不会让UI更新哦
android·ios·harmonyos
茶底世界之下6 天前
为什么预览、录制、离线导出不能共享同一个背压策略?
ios·swift
2501_916007476 天前
苹果商店iOS应用上架费用全面解析:开发者计划与审核费用计算
android·ios·小程序·https·uni-app·iphone·webview
2501_916008896 天前
如何实现iOS App代码混淆:SwiftShield使用指南
android·ios·小程序·https·uni-app·iphone·webview
2501_915909066 天前
移动端开发工具链怎么组合比较好,iOS、Android、跨端三套配置方案
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
2501_916008896 天前
怎么用 Godot 导出 iOS 应用并上架 App Store?签名字段该填什么?
android·ios·小程序·https·uni-app·iphone·webview