惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
S
Schneier on Security
P
Palo Alto Networks Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
S
Securelist
T
Threat Research - Cisco Blogs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Vulnerabilities – Threatpost
AI
AI
C
CERT Recently Published Vulnerability Notes
C
Cyber Attacks, Cyber Crime and Cyber Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Know Your Adversary
Know Your Adversary
AWS News Blog
AWS News Blog
TaoSecurity Blog
TaoSecurity Blog
O
OpenAI News
Cyberwarzone
Cyberwarzone
G
GRAHAM CLULEY
SecWiki News
SecWiki News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
Cisco Blogs
K
Kaspersky official blog
Spread Privacy
Spread Privacy
S
Security @ Cisco Blogs
Hacker News - Newest:
Hacker News - Newest: "LLM"
IT之家
IT之家
有赞技术团队
有赞技术团队
B
Blog
T
Tailwind CSS Blog
PCI Perspectives
PCI Perspectives
P
Privacy & Cybersecurity Law Blog
Last Week in AI
Last Week in AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Webroot Blog
Webroot Blog
博客园 - 叶小钗
Cisco Talos Blog
Cisco Talos Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
H
Hacker News: Front Page
The Cloudflare Blog
C
Cybersecurity and Infrastructure Security Agency CISA
美团技术团队
V
V2EX
腾讯CDC
S
SegmentFault 最新的问题
Security Archives - TechRepublic
Security Archives - TechRepublic

看川博客

我被 AI "蒸馏" 了 - 看川博客 距离上线只差一个软件著作权证书 - 看川博客 开发简报(2):开发者需要先进的工具 - 看川博客 比越狱更棘手!iOS vPhone 虚拟机成黑灰产新温床 - 看川博客 开发简报(1):拥抱 AI、别无选择 - 看川博客 糟糕!我的 OpenClaw 中了病毒 - 看川博客 今天你用了多少词元? - 看川博客 闪忆 LiveMem:把回忆做成会动的壁纸 - 看川博客 Swift 从 ObservableObject 迁移到 @Observable 的再讨论 视频帧截图(Video2Frame)专业视频抽帧截图工具 - 看川博客 录音记事本 - 专业安全的录音工具 App - 看川博客 从 Apple Distribution Managed 证书提取备案所需公钥和 SHA1 条码助手 iOS 2.0.0 升级指南 - 看川博客 SwiftUI Menu checkmark 文本对齐 - 看川博客 C++ RTTI 信息对二进制体积和安全性的影响 - 看川博客 SwiftUI 系统颜色表查询 - 看川博客 读马伯庸《长安的荔枝》 - 看川博客 SwiftUI List selection 的使用提示 - 看川博客 PHP json_encode UTF-8 中文编码问题 - 看川博客 我为什么重新运营微信公众号 - 看川博客 使用 TrollStore(巨魔) 在非越狱设备上安装任意 IPA - 看川博客 条码助手小程序更新 - 看川博客 iOS 18 中 libdyld.dylib/dyld 的一些变化 涨粉神器?解密“抖音黑科技”云端商城 - 看川博客
Swift 从 ObservableObject 迁移到 @Observable
2025-10-16 · via 看川博客

ObservableObject 协议是 SwiftUI 早期的观察机制,Swift 5.9 引入 @Observable 宏作为 Swift 观察的"现代"解决方案。本文讲解从 ObservableObject 迁移到 @Observable。

@Observable 宏方案适配 iOS 17、iPadOS 17、macOS 14、tvOS 17和watchOS 10 及以上版本,在 App 支持 OS 版本允许的的情况下,应该优先使用 @Observable。

传统方案:ObservableObject

定义:

import Combine

class UserProfile: ObservableObject {
    @Published var name: String = "Chuan"
    @Published var age: Int = 25
    
    var displayName: String {
        "\(name) (\(age))"
    }
}
  1. 导入 Combine 框架;
  2. 必须遵循 ObservableObject 协议;
  3. 使用 @Published 标记可观察的属性;

使用:

struct ProfileView: View {
    @StateObject private var profile = UserProfile()
    // 或 @ObservedObject var profile: UserProfile
    
    var body: some View {
        VStack {
            Text(profile.name)
            Text("\(profile.age)")
        }
    }
}

使用时需要 @StateObject 或 @ObservedObject 修饰 ObservableObject 对象。

@Observable 方案

定义:

import Observation

@Observable 
class UserProfile {
    var name: String = "Chuan"
    var age: Int = 25
    
    var displayName: String {
        "\(name) (\(age))"
    }
}
  1. 导入 Observation 框架;
  2. 使用 @Observable 宏;
  3. 可观察属性不需要使用 @Published 标记,Swift 会自动追踪 body 视图中读取到的所有可观察属性。

使用:

struct ProfileView: View {
    let profile: UserProfile // 不再需要 @ObservedObject 或 @StateObject 包装器
    
    var body: some View {
        VStack {
            Text(profile.name) // 自动观察 name
            Text("\(profile.age)") // 自动观察 age
        }
    }
}

很明显可以看到:@Observable 方案大大简化了设计过程,不再需要 @Published、ObservableObject、@ObservedObject 了。

另外从性能上看,@Observable 也更具优势。@Observable 能精确至对象属性的变化来更新 view,而 ObservableObject 则是整个对象变化都会通知。

追踪机制对比:

class Counter: ObservableObject {
    @Published var count = 0
    @Published var name = "Counter"
}

let counter = Counter()

// 修改任何一个 @Published 属性都会触发整个对象的更新
counter.count += 1 // 触发更新
counter.name = "New Name" // 也触发更新,即使视图只使用 count

而 @Observable 方案:

@Observable class Counter {
    var count = 0
    var name = "Counter"
}

let counter = Counter()

// SwiftUI 只会更新实际使用特定属性的视图
// 如果视图只使用 count,修改 name 不会触发视图更新

environment 的变动

将 ObservableObject 对象添加到 environment 中必须使用 environmentObject:

@main
struct BookApp: App {
    @StateObject private var profile = UserProfile()

    var body: some Scene {
        WindowGroup {
            LibraryView()
                .environmentObject(profile)
        }
    }
}

@Observable 方案中不再需要 environmentObject:

@main
struct BookApp: App {
    @State private var profile = UserProfile()

    var body: some Scene {
        WindowGroup {
            LibraryView()
                .environment(profile)
        }
    }
}

对应的读取环境变量也从原来的:

struct LibraryView: View {
    @EnvironmentObject var profile: UserProfile

    var body: some View {
        UserView(profile: profile)
    }
}

变为:

struct LibraryView: View {
    @Environment(UserProfile.self) private var profile

    var body: some View {
        UserView(profile: profile)
    }
}

@Bindable

@Bindable 是与 @Observable 宏配合使用的属性包装器,它允许将 @Observable 类型的属性转换为可绑定引用,以便在绑定的视图中可以更改可观察属性的值。

// 父视图
struct ParentView: View {
    @State private profile = UserProfile()
    
    var body: some View {
        UserForm(profile: profile) // 这里 profile 自动变为 @Bindable
    }
}

// 子视图在参数位置接收 @Bindable
struct UserForm: View {
    @Bindable var profile: UserProfile
    
    var body: some View {
        Form {
            TextField("Name", text: $profile.name) // $profile.name 将同步到 ParentView
            TextField("Age", text: $profile.age)
        }
    }
}

参考:

Migrating from the Observable Object protocol to the Observable macro