0
点赞
收藏
分享

微信扫一扫

SwiftData Error in Preview with @Previewable

倚然君 2024-11-06 阅读 7

Error: This store went missing? Optional(SwiftData.PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID...

The error is usually caused by how the modelContainer is initialized, and most of the time, it happens while Xcode renders the preview.

This means SwiftData can't find the model using the model's identifier.

Consider we have a preview like the one below:

#Preview {
@Previewable @State var modelContainer = try! ModelContainer.previewContainer()

SomeView().modelContainer(modelContainer)
}

And the previewContainer function is defined as below:

extension ModelContainer {
static func previewContainer() {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try? ModelContainer(for: [Record.self], configurations: config)
// insert some sample data for preview
Task { @MainActor in
let context = container?.mainContext
context.insert(Record())
}
return container
}
}

If you turn on the Xcode preview, it works, but after a few seconds, it crashes and shows the above error.

It is typically because the preview is refreshed after your source code changes and the previewContainer is run again.

Each time it runs, the previous context and models are destroyed, but the swiftUI preview still holds a reference to that old model.

The inconsistency causes the error: the old model's id can't be found in the new context, and the new context does not have a model whose id is identical to the old model's id.

Note, by saying id, we're talking about the PersistentIdentifier of the model generated by SwiftData, not a custom property set by us. Even if we set a property called id in the model, it does not affect the PersistentIdentifier of the model.

So how to resolve the problem? Since the reason is every update of the preview will call the try! ModelContainer.previewContainer() function, and returns a new container, we can simply make the container a static property that will not be changed during the lifetime of the app.

extension ModelContainer{
static let previewContainer: ModelContainer? = {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try? ModelContainer(for: [Record.self], configurations: config)

Task { @MainActor in
let context = container?.mainContext
context.insert(Record())
}

return container
}()
}

In this way, the previewContainer will be called only once when the app starts, avoiding consistency between preview refreshes, and the error does not appear anymore.

本文由博客一文多发平台 OpenWrite 发布!

举报

相关推荐

0 条评论