TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

SOLVED: SwiftData & CloudKit

Forums > SwiftUI

I am creating an app and starting to try out SwiftData for the first time in a app. I am going to post code so that y'all have has much info as possible.

First Question: I am under the impression that if a model has a relationship to another model and that model has a relationship to another model you only need to include the first model in the container, not totally clear on that. I would like some clarification on that as well.

Second Question I have my app setup for CloudKit and I get the following error when running: Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: SwiftData.SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer)

If I turn off CloudKit under capabilities my app launches just fine. Heres my setup: I would like to know what I'm doing wrong.

Any anwsers to my 2 questions would be most appreciated.

**Models**

@Model
class ContactModel {
    // MARK: - Properties
    var anniversary: Date = Date.distantPast
    var birthDay: Date = Date.distantPast
    var firstName: String = ""
    var lastName: String = ""
    var streetAddress: String = ""
    var city: String = ""
    var state: String = ""
    var postalCode: String = ""
    var country: String = ""
    var isoCountryCode: String = ""
    var uniqueIDKey: String = ""
    @Attribute(.externalStorage) var image: Data? = nil

    // MARK: - Relationships
    @Relationship(deleteRule: .cascade, inverse: \EventModel.contact)
    var events: [EventModel]?

    @Relationship(deleteRule: .nullify)
    var crowd: CrowdModel?

    init(
        anniversary: Date,
        birthDay: Date,
        firstName: String,
        lastName: String,
        streetAddress: String,
        city: String,
        state: String,
        postalCode: String,
        country: String,
        isoCountryCode: String,
        uniqueIDKey: String,
        image: Data? = nil,
        events: [EventModel]? = nil,
        crowd: CrowdModel? = nil
    ) {
        self.anniversary = anniversary
        self.birthDay = birthDay
        self.firstName = firstName
        self.lastName = lastName
        self.streetAddress = streetAddress
        self.city = city
        self.state = state
        self.postalCode = postalCode
        self.country = country
        self.isoCountryCode = isoCountryCode
        self.uniqueIDKey = uniqueIDKey
        self.image = image
        self.events = events
        self.crowd = crowd
    }
}

@Model
class CrowdModel {
    // MARK: - Properties
    var name: String = ""

    // MARK: - Relationships
    @Relationship(deleteRule: .nullify, inverse: \ContactModel.crowd)
    var contacts: [ContactModel]?

    init(name: String, contacts: [ContactModel]? = nil) {
        self.name = name
        self.contacts = contacts
    }
}

@Model
class EventModel {
    var name: String = ""
    var date: Date = Date.distantPast
    var eventType: Int32 = 0
    var notes: String = ""

    // MARK: - Relationships
    @Relationship(deleteRule: .cascade, inverse: \ReminderModel.event)
    var reminders: [ReminderModel]?

    @Relationship(deleteRule: .nullify)
    var contact: ContactModel?

    init(name: String, date: Date, eventType: Int32, notes: String, reminders: [ReminderModel]? = nil, contact: ContactModel? = nil) {
        self.name = name
        self.date = date
        self.eventType = eventType
        self.notes = notes
        self.reminders = reminders
        self.contact = contact
    }
}

@Model
class ReminderModel {
    // MARK: - Properties
    var howManyDaysFrom: String = ""
    var date: Date = Date.distantPast
    var reminderID: String = ""

    // MARK: - Relationships
    @Relationship(deleteRule: .nullify)
    var event: EventModel?

    init(howManyDaysFrom: String, date: Date, reminderID: String, event: EventModel? = nil) {
        self.howManyDaysFrom = howManyDaysFrom
        self.date = date
        self.reminderID = reminderID
        self.event = event
    }
}

**App Setup**

@main
struct EventPlannerApp: App {
    // MARK: - Environment
    @Environment(\.scenePhase) var scenePhase
    @Environment(\.modelContext) var mc

    // MARK: - SwiftData
    let container: ModelContainer

    init() {
        let schema = Schema([ContactModel.self, CrowdModel.self, EventModel.self, ReminderModel.self])
        let config = ModelConfiguration("EventPlanner", schema: schema)
        do {
            container = try ModelContainer(for: schema, configurations: config)
        } catch {
            fatalError("Couldn't load or configure container")
        }
    }

    // MARK: - State
    @State var jsonData = LoadJSONData()
    @State var contactStore = ContactStore()

    var body: some Scene {
        WindowGroup {
            MainAppView()
                .environment(jsonData)
                .environment(contactStore)
                .onAppear {
                    // This suppresses constraint warnings
                    UserDefaults.standard.setValue(false, forKey: "_UIConstraintBasedLayoutLogUnsatisfiable")
                }
                .defaultAppStorage(UserDefaults(suiteName: AC.appGroup.rawValue)!)
        }
        .modelContainer(container)
        .onChange(of: scenePhase) {
            switch scenePhase {
                case .background:
                    #warning("Add code to save database and delete break statement")
                    break
                case .active, .inactive:
                    break
                @unknown default:
                    fatalError("fatal error for .onChange(of: scenePhase) modifier")
            }
        }
    }
}

   

Ok, I figured it out. The problem was in the following code: I was using @Environment(\.modelContext) var mc before the container had been initialized.

I would still love to know more information on my first question:

First Question: I am under the impression that if a model has a relationship to another model and that model has a relationship to another model you only need to include the first model in the container, not totally clear on that. I would like some clarification on that as well.

   

Hacking with Swift is sponsored by String Catalog.

SPONSORED Get accurate app localizations in minutes using AI. Choose your languages & receive translations for 40+ markets!

Localize My App

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.