简体   繁体   中英

How to use func assign(_ object: Any, to store: NSPersistentStore) of a NSManagedObjectContext?

Setup:
My app uses 2 persistent stores managed by a single persistent store coordinator that is used by several managed object contexts. Both persistent stores store the same entities.
It is required that any inserts, updates and deletes of managed objects are only done in one of both persistent stores, and the app can select the persistent store.

Problem:
In order to store a managed object only in one persistent store, I want to use func assign(_ object: Any, to store: NSPersistentStore) of a NSManagedObjectContext . The docs say

Specifies the store in which a newly inserted object will be saved.

Question:
What means „newly inserted“?

  • Can I assign a persistent store as long as the object has never been saved by its context?
  • Could I use, eg, a willSaveObjectsNotification to loop though all registeredObjects of the context and assign the required persistent store?

When the app switches the persistent store, I would then reset the contexts so that all managed objects would be fetched newly, and the required persistent store could be set again in the willSaveObjectsNotification notification.
Is this the right way to go?

That function can only be used for a managed object that does not belong to any managed object context yet. It's possible to create an instance using an entity description, that's not part of any context. For example you can use init(entity:,insertInto:) with a nil for the second argument. If you do that, you can later use the `assigns function to insert it into a context.

If a managed object is already associated with a context, you can't use this function to move it to a different one. You would need to create a new instance in the new context and copy all the property values.

Based on Tom Harrington's answer, I did the following tests.
The result is:
As long as a managed object has never been saved to a persistent store, one can use assign(_:to:) to define one of several persistent stores into which the object will be saved later.

My code:

// Setup:
// privateStore and sharedStore are persistent stores to which the Item entity is assigned.
// Item is a managed object whose entity is assigned to the persistent stores privateStore and sharedStore.
// It has an attribute "name" to distibguish it from other objects.

// Create for privateStore and sharedStore one fetch request respectively for an Item with name "item"
let namePredicate = NSPredicate(format: "name == %@", "item")

let privateStoreItemFetchRequest = NSFetchRequest<Item>(entityName: Item.entityName)
privateStoreItemFetchRequest.predicate = namePredicate
privateStoreItemFetchRequest.affectedStores = [privateStore]

let sharedStoreItemFetchRequest = NSFetchRequest<Item>(entityName: Item.entityName)
sharedStoreItemFetchRequest.predicate = namePredicate
sharedStoreItemFetchRequest.affectedStores = [sharedStore]

// 1st test: Create an Item without a context, assign it to a store, insert it into a context and try to fetch it from both stores
let item1 = Item(entity: itemEntity, insertInto: nil)
item1.name = "item"
viewContext!.assign(item1, to: privateStore)
viewContext!.insert(item1)
let items1InPrivateStore = try? viewContext!.fetch(privateStoreItemFetchRequest)
print("Test 1: privateStore: \(items1InPrivateStore ?? [])") // Prints item1
let items1InSharedStore = try? viewContext!.fetch(sharedStoreItemFetchRequest)
print("Test 1: sharedStore: \(items1InSharedStore ?? [])") // Prints []

// 2nd test: Create an Item and insert it into a context, assign it to a store and try to fetch it from both stores
let item2 = Item(entity: itemEntity, insertInto: viewContext!)
item2.name = "item"
viewContext!.assign(item2, to: privateStore)
let items2InPrivateStore = try? viewContext!.fetch(privateStoreItemFetchRequest)
print("Test 2: privateStore: \(items2InPrivateStore ?? [])") // Prints item1 and item2
let items2InSharedStore = try? viewContext!.fetch(sharedStoreItemFetchRequest)
print("Test 2: sharedStore: \(items2InSharedStore ?? [])") // Prints []

// Save the context and try to fetch both items from both stores
do {
    try viewContext!.save()
} catch { fatalError() }
let items3InPrivateStore = try? viewContext!.fetch(privateStoreItemFetchRequest)
print("Test 3: privateStore: \(items3InPrivateStore ?? [])") // Prints item1 and item2
let items3InSharedStore = try? viewContext!.fetch(sharedStoreItemFetchRequest)
print("Test 3: sharedStore: \(items3InSharedStore ?? [])") // Prints []

// item1 has been assigned above to the privateStore. Try now to assign it to the sharedStore
viewContext!.assign(item1, to: sharedStore) // Run time error: "Can't reassign an object to a different store once it has been saved."

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM