swiftxcodecore-dataswiftuinsmanagedobject

How to use CoreData Objects temporarily without needing to insert them into a Context?


Context

I am working on a feature, that allows users to add Components to CoreData. Those Components are obviously NSManagedObjects inserted and saved into a Context. In addition, I also want to give the user a variety of predefined Components. However, I do not like the idea of populating those predefined ones into CoreData at the first App Launch, since this is really prone to bugs, especially when utilising CloudKit. So my idea was to generate a List of predefined NSManagedObjects without inserting them into a Context, which would make them temporarily, but they could be used in the same way as the real ones. However, as far as I understand, creating NSManagedObjects without a Context isn't really working.


Code

let predefinedComponents: [Component] {
    var components: [Component] = []

    for name in names {
        let component = Component() // This was my idea of creating a temporary NSManagedObject without inserting it into a Context.
        component.name = name

        components.append(component)
    }

    return components
}

struct ComponentsView: View {
    @FetchRequest(sortDescriptors: [SortDescriptor(\.name)]) private var components: FetchedResults<Component>

    var body: some View {
        ForEach(allComponents) { component in 
            ComponentRow(component: component)
        }
    }

    private var allComponents: [Component] {
        var allComponents: [Component] = predefinedComponents

        for component in components {
            allComponents.append(component)
        }

        return allComponents
    }
}

struct ComponentRow: View {
    @ObservedObject var component: Component

    var body: some View {
        Text(component.name)
    }
}

Question

How can I achieve my goal described above while being able to work with predefined Components without having to populate them into CoreData at the first AppLaunch?


Solution

  • You can create "free floating" managed objects that don't belong to a context but you need to provide the entity description to do it-- so you would use Component(entity:insertInto:). The first argument is the NSEntityDescription for Component. The second one is a context, but it's an optional, so you can make it nil. If you wanted to add it to a context later, use NSManagedObjectContext.insert().

    It might be better to use an in-memory persistent store instead of a SQLite store. Then you would have a context that only existed while the app was running but did not save to a file. You can set one of those up with NSPersistentContainer if you change the persistent store description.

    I can't tell from your question which of these would be better for you.