Reading Apple Docs: PreviewModifier Step by Step
讀 Apple 文件的方法:以 PreviewModifier 為例
Apple 在 What’s new in SwiftData – WWDC24 裡用一句話介紹了 PreviewModifier:
To use preview traits, you can create a new struct that conforms to
PreviewModifierwhich has two functions: one for setting up a shared context for the preview, and another to apply the shared context to a view. For SwiftData previews, you can vend aModelContaineras the shared context, creating aModelConfigurationthat stores data in memory only.
看完這句話,你應該要能寫出一個完整的 PreviewModifier 實作。
但如果你跟我一樣,看完之後只覺得「每個字都認識,合在一起不知道在說什麼」——這篇就是給你的。
拆解方法:一段一段對應程式碼
Apple 的 WWDC 講稿風格是把很多前置知識壓縮成一句話。要讀懂它,需要三件事:
- 把句子切成片段
- 每個片段對應到一段程式碼
- 標出「Apple 沒說、但你需要自己去查的東西」
以下用這個方法拆解那句話。
片段 1
“create a new struct that conforms to
PreviewModifier“
對應:
1
2
3
struct SampleDataPreviewModifier: PreviewModifier {
// ...
}
Apple 沒說的: PreviewModifier 是哪來的?它是 SwiftUI 的 protocol,iOS 18+ 才有。你需要 import SwiftUI。
片段 2
“which has two functions”
對應:這個 protocol 要求你實作兩個 method。
Apple 沒說的: 這兩個 method 的確切簽名是什麼?你要去查 PreviewModifier 文件 才知道:
1
2
3
4
5
// 第一個
static func makeSharedContext() async throws -> Self.Context
// 第二個
func body(content: Self.Content, context: Self.Context) -> some View
Context 是一個 associated type,你自己決定它是什麼型別。
片段 3
“one for setting up a shared context for the preview”
對應:第一個 method makeSharedContext()。
1
2
3
static func makeSharedContext() async throws -> ??? {
// 在這裡準備 Preview 需要的東西
}
??? 要填什麼?看下一段。
片段 4
“For SwiftData previews, you can vend a
ModelContaineras the shared context”
對應:Context = ModelContainer。所以回傳型別是 ModelContainer:
1
2
3
static func makeSharedContext() async throws -> ModelContainer {
// 建一個 ModelContainer
}
Apple 沒說的: 你需要 import SwiftData。
片段 5
“creating a
ModelConfigurationthat stores data in memory only”
對應:在 makeSharedContext() 裡面用 isStoredInMemoryOnly: true:
1
2
3
4
5
static func makeSharedContext() async throws -> ModelContainer {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try ModelContainer(for: CareEvent.self, configurations: [config])
return container
}
Apple 沒說的: ModelContainer(for:configurations:) 的第一個參數要填你的 Model 型別。而且如果你想 Preview 有資料可以看,要自己塞假資料(Apple 這句話完全沒提假資料的事)。
片段 6
“and another to apply the shared context to a view”
對應:第二個 method body(content:context:)。
1
2
3
func body(content: Content, context: ModelContainer) -> some View {
content.modelContainer(context)
}
content 是你的 Preview View,context 是剛才 makeSharedContext() 回傳的 ModelContainer。用 .modelContainer() 注入就好。
組裝起來
把六個片段組在一起:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import SwiftData
import SwiftUI
struct SampleDataPreviewModifier: PreviewModifier {
static func makeSharedContext() async throws -> ModelContainer {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try ModelContainer(for: CareEvent.self, configurations: [config])
// 塞假資料(Apple 沒提,但 Preview 需要)
CareEventSeeder.seedForPreview(into: container.mainContext)
return container
}
func body(content: Content, context: ModelContainer) -> some View {
content.modelContainer(context)
}
}
Apple 那句話完全沒提到的東西
寫完 struct 之後,你還需要:
1. 註冊成 PreviewTrait
讓 #Preview(traits:) 認得你的 modifier:
1
2
3
extension PreviewTrait where T == Preview.ViewTraits {
@MainActor static var sampleData: Self = .modifier(SampleDataPreviewModifier())
}
Apple 那句話完全沒提到這一步。你要看 WWDC session 的 demo 或查文件才知道。
2. 使用方式
1
2
3
#Preview(traits: .sampleData) {
DailyTimelineView()
}
traits: 參數也沒有在那句話裡出現。
結論:Apple 文件的讀法
Apple 的文件和 WWDC 不是教學,是規格說明書。它假設你已經知道:
- protocol 怎麼用
- associated type 怎麼填
- 去哪裡查 method 簽名
如果你覺得「看了 Apple 的說明還是不會寫」,不是你的問題。是 Apple 把「教學」和「規格」混在一起,卻用規格的寫法寫教學。
讀的時候,試試這個流程:
- 把句子切成片段
- 每個片段查一次文件(不是整篇看,是只查那個 API 的簽名)
- 標出「Apple 沒說的」(那些就是你需要額外查的)
- 先寫最小的 compilable 版本,再慢慢加功能
這比「看完整句話然後試著一次寫完」有效得多。