Why doesn’t NSFetchRequest.shouldRefreshRefetchedObjects work?

寵の児 提交于 2021-02-07 18:35:21

问题


I’m trying to update and save a managed object in one context and then access the updated attribute value in another context. The documentation for shouldRefreshRefetchedObjects says:

By default when you fetch objects, they maintain their current property values, even if the values in the persistent store have changed. Invoking this method with the parameter YES means that when the fetch is executed, the property values of fetched objects are updated with the current values in the persistent store. This is a more convenient way to ensure that managed object property values are consistent with the store than by using refreshObject:mergeChanges: (NSManagedObjetContext) for multiple objects in turn.

So I thought that by setting this to true I would get current values after refetching, without having to manually refresh the individual objects. However, that does not seem to be the case. On macOS 10.14.5, the fetch request will select the proper objects based on the property values in the store, but the objects in memory still have stale values.

Here’s some sample code to illustrate the problem. I expect it to print Old New New, but instead it prints Old Old New.

import Foundation
import CoreData

class Entity: NSManagedObject {
    @NSManaged var attribute: String
}

let attribute = NSAttributeDescription()
attribute.name = "attribute"
attribute.attributeType = .stringAttributeType
let entityDescription = NSEntityDescription()
entityDescription.name = "Entity"
entityDescription.properties = [attribute]
entityDescription.managedObjectClassName = Entity.className()
let model = NSManagedObjectModel()
model.entities = [entityDescription]

let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
try! coordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: [:])

let writeContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
writeContext.persistentStoreCoordinator = coordinator
let readContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
readContext.persistentStoreCoordinator = coordinator

let writeEntity = Entity(entity: entityDescription, insertInto: writeContext)
writeContext.performAndWait {
    writeEntity.attribute = "Old"
    try! writeContext.save()
}

var readEntity: Entity? = nil
readContext.performAndWait {
    let request = NSFetchRequest<Entity>(entityName: entityDescription.name!)
    readEntity = try! readContext.fetch(request).first!
    // Initially the attribute should be Old, and that's what's printed
    print(readEntity!.attribute)
}

writeContext.performAndWait {
    writeEntity.attribute = "New"
    try! writeContext.save()
}

readContext.performAndWait {
    let request = NSFetchRequest<Entity>(entityName: entityDescription.name!)
    request.shouldRefreshRefetchedObjects = true
    _ = try! readContext.fetch(request)
    // Now the attribute should be New, but it is still Old
    print(readEntity!.attribute)

    readContext.refresh(readEntity!, mergeChanges: false)
    _ = try! readContext.fetch(request)
    // However, manually refreshing and fetching again does update it to New
    print(readEntity!.attribute)
}

I’m aware of refreshAllObjects(), but that:

  1. Potentially affects many more objects that don’t need to be updated right now.
  2. Doesn’t provide control over merging changes.
  3. Posts a change notification.

shouldRefreshRefetchedObjects seems to be exactly what I want; it just doesn’t seem to do anything. The best workaround seems to be to individually refresh the objects, but I’m guessing that’s inefficient.

来源:https://stackoverflow.com/questions/56634268/why-doesn-t-nsfetchrequest-shouldrefreshrefetchedobjects-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!