You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI传递SwiftData @Model对象参数时预览编译报错求助

SwiftData @Model对象传递及预览报错解决

问题场景

使用Xcode 15 beta 2开发SwiftData+SwiftUI多视图项目,将@Model标记的Item对象作为参数传入DetailView时,DetailView的预览代码抛出编译错误:
"Type 'Item' does not conform to protocol 'PersistentModel'"

相关代码

ContentView

import SwiftUI
import SwiftData

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var items: [Item]
    
    @State private var selection: Item?
    
    var body: some View {
        NavigationSplitView {
            List(selection: $selection) {
                ForEach(items) { item in
                        Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
                }
                .onDelete(perform: deleteItems)
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
        } detail: {
            DetailView(selection: selection)
        }
        .navigationSplitViewStyle(.balanced)
    }

    private func addItem() {
        withAnimation {
            let newItem = Item(timestamp: Date())
            modelContext.insert(newItem)
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            for index in offsets {
                modelContext.delete(items[index])
            }
        }
    }
}

#Preview {
    ContentView()
        .modelContainer(for: Item.self, inMemory: true)
}

DetailView

import SwiftUI
import SwiftData

struct DetailView: View {
    var selection: Item?
    
    var body: some View {
        if let item = selection {
            Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
        } else {
            Text("nothing selected")
        }
    }
}

#Preview {
    return DetailView(selection: Item(timestamp: Date()))
        .modelContainer(for: Item.self, inMemory: true)
}

Item

import Foundation
import SwiftData

@Model
final class Item {
    var timestamp: Date
    
    init(timestamp: Date) {
        self.timestamp = timestamp
    }
}

解决方案

1. 修正预览代码:让@Model实例关联ModelContext

直接初始化的Item实例未绑定到任何ModelContext,无法被识别为PersistentModel。需要先创建ModelContainer,将实例插入上下文后再传入DetailView:

修改后的DetailView预览代码:

#Preview {
    do {
        // 创建内存容器
        let container = try ModelContainer(
            for: Item.self,
            configurations: ModelConfiguration(inMemory: true)
        )
        // 创建Item实例并插入上下文
        let previewItem = Item(timestamp: Date())
        container.mainContext.insert(previewItem)
        // 传入关联了上下文的实例
        return DetailView(selection: previewItem)
            .modelContainer(container)
    } catch {
        return Text("预览初始化失败:\(error.localizedDescription)")
    }
}

2. 确认@Model对象的传递方式

你在ContentView中通过@Query获取Item实例,再将selection传给DetailView的方式是完全正确的。这类从有效ModelContext中获取的实例,本身已经符合PersistentModel协议,可以直接作为参数传递。

原因说明

@Model修饰的类会自动实现PersistentModel协议,但该协议的有效性依赖于实例是否被关联到某个ModelContext。直接调用初始化方法创建的实例处于"游离"状态,未绑定上下文,因此在预览中会触发协议不兼容的报错。必须通过modelContext.insert(_:)将其纳入容器管理后,才能正常使用。

内容的提问来源于stack exchange,提问作者Syd Polk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 04:57:02