建筑师之家IOS / NOTES
← 全部笔记

性能

MainActor 不是把所有东西都标上

界面类型隔离到主线程。解码、解析、入库放在外面,再把结果送回来。

Swift 并发里,最容易做成的“优化”是给整个模块加上 @MainActor。警告没了,重活也回到主线程上。隔离的意义是划清谁必须在主线程,不是让编译器闭嘴。

谁该在主线程

UIViewController、SwiftUI 的 View、任何直接碰 UIKit 的类型,放在 MainActor。网络模型、解码、图片缩放、数据库写入,不要标 MainActor。它们返回 Sendable 的结果,界面再收。

struct Note: Sendable {
    var id: String
    var text: String
}

func parseNotes(from data: Data) async throws -> [Note] {
    try await Task.detached {
        try JSONDecoder().decode([Note].self, from: data)
    }.value
}

@MainActor
final class NoteListModel {
    var notes: [Note] = []

    func reload(data: Data) async throws {
        notes = try await parseNotes(from: data)
    }
}

从 MainActor 调用一个没有隔离的 async 函数,中间那段可以离开主线程。如果那个函数内部又立刻 await MainActor.run 去做解析,隔离等于没做。

不要用锁补隔离

已经有 actor 或 MainActor,就不要再套 NSLock 去保护同一份状态。两套规则叠在一起,死锁更难看。共享可变状态收进一个 actor,外面只拿值。

编译器提示“这个调用要等主线程”时,先问这件工作是不是界面。是,就标对类型。不是,就把工作移出这个类型,而不是把调用方也标成 MainActor。