gpt4 book ai didi

macos - 为什么 NSFetchRequest.shouldRefreshRefetchedObjects 不起作用?

转载 作者:行者123 更新时间:2023-12-04 11:57:59 24 4
gpt4 key购买 nike

我正在尝试在一个上下文中更新和保存托管对象,然后在另一个上下文中访问更新的属性值。 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.



所以我认为通过将其设置为 true我将在重新获取后获取当前值,而无需手动刷新单个对象。然而,情况似乎并非如此。在 macOS 10.14.5 上,获取请求将根据存储中的属性值选择合适的对象,但内存中的对象仍然具有陈旧的值。

下面是一些示例代码来说明问题。我希望它打印 Old New New ,而是打印 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)
}

我知道 refreshAllObjects() ,但是:
  • 可能会影响更多现在不需要更新的对象。
  • 不提供对合并更改的控制。
  • 发布变更通知。
  • shouldRefreshRefetchedObjects似乎正是我想要的;它似乎什么也没做。最好的解决方法似乎是单独刷新对象,但我猜这是低效的。

    最佳答案

    简短的回答是:这是框架中的一个错误。问题中的代码应该可以工作,但不能,因为 shouldRefreshRefetchedObjects不像宣传的那样工作。
    我还尝试了一些其他的代码变体。我将其更改为使用 SQLite 持久存储,以便我可以打开 SQLite 调试并查看它是否告诉我任何有趣的事情。获取意外结果的 fetch 在 Xcode 控制台中打印这些消息:

    CoreData: annotation:  with values: (
    "<JunkCDCmd.Entity: 0x100704760> (entity: Entity; id: 0x9e9e44e129d3565d
    <x-coredata://3F8EC946-9EF7-4A62-AEF2-A8670185E23C/Entity/p1>;
    data: {\n attribute = Old;\n})"
    )
    越来越 Old ,这不是这里的预期。结果很可能来自托管对象上下文的缓存,这表明 shouldRefreshRefetchedObjects没有被框架检查。
    我还尝试了其他一些似乎不太可能有帮助但我不能不尝试就排除的事情。我用过 shouldRefreshRefetchedObjects在最初的 fetch 上,因为为什么不呢。我试着保留 readEntity从第一次获取而不是让它超出范围。我尝试嵌套 writeContext.performAndWaitreadContext.performAndWait ,以防范围相关。我将获取结果保存在变量中,而不是使用 _以确保结果不是意外 deallocard 或其他东西。正如预期的那样,这些都没有任何区别。
    赏金要求

    A thorough explanation of why in fact this does not work and how to implement it in whatever place it is that it should work.


    精确如果没有框架的源代码,就不可能知道它不起作用的原因。没有这个我们只能推测。它显然坏了,看起来好像坏了,因为它没有检查 shouldRefreshRefetchedObjects .如果它对您不起作用(并且看起来它不可能对您起作用),则向 Apple 提交错误并希望最好。
    至于如何实现它,如果此设置正是您所需要的,那么就没有确切的替代方案。刷新值的选项包括(无特定顺序)
  • 使用 refresh(_:mergeChanges:) 强制对象在获取之前成为错误,如问题中所述与 false对于第二个论点。如果您有一堆受影响的对象,这可能会很尴尬。
  • 使用 refresh(_:mergeChanges:) 直接刷新对象与 true对于第二个论点。您无需重新获取。如果您有一堆受影响的对象,这可能会很尴尬。
  • 使用 refreshAllObjects() 刷新所有注册对象,它具有问题中描述的缺点。
  • 合并来自 NSManagedObjectContextDidSave 的更改通知(又名 Notification.Name.didSaveObjectsNotification)。
  • 关于macos - 为什么 NSFetchRequest.shouldRefreshRefetchedObjects 不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56634268/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com