setting up SwiftData modelContainer for previews compatible with CloudKit

76 Views Asked by At

My Swiftdata App (using Apples WWDC23 SampleTrips App PreviewSampleData for generating #Previews) keeps crashing its canvas previews after enabling CloudKit. The crash always happens when trying to initialise the in-memory ModelContainer:

actor PreviewSampleData {

    @MainActor
    static var container: ModelContainer = {
        return try! inMemoryContainer()
    }()

    static var inMemoryContainer: () throws -> ModelContainer = {
        let schema = Schema([Trip.self, BucketListItem.self, LivingAccommodation.self])
        let configuration = ModelConfiguration(isStoredInMemoryOnly: true)
        let container = try! ModelContainer(for: schema, configurations: [configuration]) <—- crash continues to happen here
        let sampleData: [any PersistentModel] = [
            Trip.preview, BucketListItem.preview, LivingAccommodation.preview
        ]
        Task { @MainActor in
            sampleData.forEach {
                container.mainContext.insert($0)
            }
        }
        return container
    }
}

I thought I’d share here the solution I’ve found after being confused by the error messages I received (failed to load stores) and lots of trial and errors.

After enabling CloudKit in Capabilities I let Xcode create a NEW CloudKit container. Then, the App had to run on a Simulator SIGNED IN to an Apple developer account. This synced the Swiftdata Schema of the App with the CloudKit container Schema.

After this, the canvas previews stopped crashing.

Important to also mind current CloudKit limitations concerning @Model objects as they can cause errors that are hard to track down. In your @Model…

  • don’t use @Attribute(.unique)
  • Don’t use @Relationship(.deny)
  • All attributes need to be either optionals or have a default value.

As per https://forums.developer.apple.com/forums/thread/731401 also make sure that @Relationship's are optional and initiated eg. As

@Model final public class MainItem { var title: String?

@Relationship(deleteRule: .cascade)
var childs: [ChildItem]?

init(title: String? = nil, childs: [ChildItem]? = []) {
    self.title = title
    self.childs = childs
}

}

@Model final public class ChildItem { var timestamp: Date?

// Add inverse as a simple variable
var item: MainItem?

init(timestamp: Date? = nil, item: MainItem? = nil) {
    self.timestamp = timestamp
    self.item = item
}

}

The crucial part that stopped preview crashes with the ‘Backingdata.swift Unknown Type … ‘ error is childs: [ChildItem]? = [] NOT childs: [ChildItem]? = nil

0

There are 0 best solutions below