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

Time:09-15

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?

CodePudding user response:

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.

CodePudding user response:

The easiest and most elegant way is to create a "throwaway scratchpad" context just for the pre-defined Components.

This scratchpad context will be a child of the viewContext, or any background context depending on your use case.

This is how you create the scratchpad:

let scratchpadContext = NSManagedObjectContext(.mainQueue)
scratchpadContext.parent = dataProvider.container.viewContext

The example above creates a context for the main queue, which I assume is your case based on your question. But if you need to access it from a background thread, you initialise it with .privateQueue.

So, as long as you don't save the scratchpadContext, your temporary pre-defined Components will never be saved on your Persistent store. And when it's de-initialised, any NSManagedObject that you've created with it will be thrown away.

  • Related