如何判断我的 NSManagedObject 是否驻留在只读 NSPersistentStore 中?
How Can I Tell If My NSManagedObject Resides in a Read Only NSPersistentStore?
我想将只读 example/tutorial 数据添加到我基于 Core Data 的 macOS 应用程序。
我将在包含示例数据的应用程序包中包含一个 SQL 文件。我的 NSPersistentContainer 将有 2 个 NSPersistentStores,一个可写,一个只读。我的模型只有默认配置,因为两家商店的模型相同。
我的 UI 需要知道显示的数据是否是只读的,例如,阻止此数据被拖动。
我知道 NSManagedObject 不支持只读状态,请参阅: ...和文档。
我认为最好的方法是将只读 属性 添加到我的 NSManagedObject 派生 class 中,以便在必要时进行查询。但是,我看不出如何轻松设置此 属性!我找不到从 NSManagedObject 到 NSPersistentStore 的直接 link。
我可以设置一个 NSFetchRequest 并指定只读存储并查看 NSManagedObject 是否在其中,但这似乎有点荒谬。
请问我是否漏掉了更明显的东西?
感谢 pbasdf 的建议...
我找不到实现此目标的直接方法。我不得不放弃使用 NSPersistentContainer
来简化我的核心数据堆栈。但是,如果您需要只读图形的一小部分,我认为这是一个相当优雅的解决方案。
我将 NSPersistentStoreCoordinator
子类化以缓存添加到其中的任何只读存储的 NSManagedObjectIDs
:
class GraphStoreCoordinator: NSPersistentStoreCoordinator
{
override init(managedObjectModel model: NSManagedObjectModel)
{
readOnlyTestContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
super.init(managedObjectModel: model)
readOnlyTestContext.persistentStoreCoordinator = self
NotificationCenter.default
.addObserver(forName: .NSPersistentStoreCoordinatorStoresDidChange,
object: self, queue: nil) { [unowned self] notification in
// userInfo will be in this form for add/remove keys - not supporting migration here
guard let userInfo = notification.userInfo as? [String: [NSPersistentStore]] else {
unhandledError("Invalid userInfo for NSPersistentStoreCoordinatorStoresDidChange.") }
userInfo[NSAddedPersistentStoresKey]?.forEach { self.didAddStore([=10=]) }
userInfo[NSRemovedPersistentStoresKey]?.forEach { self.didRemoveStore([=10=]) }
}
}
deinit {
NotificationCenter.default
.removeObserver(self, name: .NSPersistentStoreCoordinatorStoresDidChange, object: self)
}
private func didAddStore(_ store: NSPersistentStore) {
guard store.isReadOnly else { return }
var addedObjects = Set<NSManagedObjectID>()
baseEntityNames.forEach { entityName in
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: entityName)
fetchRequest.affectedStores = [store]
do {
let addedEntityObjects = try readOnlyTestContext.fetch(fetchRequest)
addedObjects = addedObjects.union(addedEntityObjects.map { [=10=].objectID })
} catch {
unhandledError("Failed to fetch all \(entityName) for read only check: \(error)") }
}
readOnlyObjects[store.identifier] = addedObjects
}
private func didRemoveStore(_ store: NSPersistentStore) {
guard store.isReadOnly else { return }
readOnlyObjects.removeValue(forKey: store.identifier)
}
/// Returns the minimum set of entities that can be fetched for readonly checking
private lazy var baseEntityNames: [String] = {
return managedObjectModel.entitiesByName.compactMap { .superentity == nil ? [=10=] : nil }
}()
private var readOnlyTestContext: NSManagedObjectContext
/// Readonly objectIDs keyed per persistent store
private var readOnlyObjects = [String : Set<NSManagedObjectID>]()
internal func isObjectReadOnly(_ objectID: NSManagedObjectID) -> Bool {
return readOnlyObjects.contains(where: { .contains(objectID) } )
}
}
然后我向 NSManagedObject
添加了一个扩展,以查询其 NSPersistentStoreCoordinator
的只读状态:
public extension NSManagedObject
{
/// Does this managed object reside in a read-only persistent store?
var isReadOnly: Bool {
guard let coordinator = managedObjectContext?
.persistentStoreCoordinator as? GraphStoreCoordinator else {
unhandledError("Should only check readonly status in a GraphStoreCoordinator") }
return coordinator.isObjectReadOnly(objectID)
}
}
我想将只读 example/tutorial 数据添加到我基于 Core Data 的 macOS 应用程序。
我将在包含示例数据的应用程序包中包含一个 SQL 文件。我的 NSPersistentContainer 将有 2 个 NSPersistentStores,一个可写,一个只读。我的模型只有默认配置,因为两家商店的模型相同。
我的 UI 需要知道显示的数据是否是只读的,例如,阻止此数据被拖动。
我知道 NSManagedObject 不支持只读状态,请参阅:
我认为最好的方法是将只读 属性 添加到我的 NSManagedObject 派生 class 中,以便在必要时进行查询。但是,我看不出如何轻松设置此 属性!我找不到从 NSManagedObject 到 NSPersistentStore 的直接 link。
我可以设置一个 NSFetchRequest 并指定只读存储并查看 NSManagedObject 是否在其中,但这似乎有点荒谬。
请问我是否漏掉了更明显的东西?
感谢 pbasdf 的建议...
我找不到实现此目标的直接方法。我不得不放弃使用 NSPersistentContainer
来简化我的核心数据堆栈。但是,如果您需要只读图形的一小部分,我认为这是一个相当优雅的解决方案。
我将 NSPersistentStoreCoordinator
子类化以缓存添加到其中的任何只读存储的 NSManagedObjectIDs
:
class GraphStoreCoordinator: NSPersistentStoreCoordinator
{
override init(managedObjectModel model: NSManagedObjectModel)
{
readOnlyTestContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
super.init(managedObjectModel: model)
readOnlyTestContext.persistentStoreCoordinator = self
NotificationCenter.default
.addObserver(forName: .NSPersistentStoreCoordinatorStoresDidChange,
object: self, queue: nil) { [unowned self] notification in
// userInfo will be in this form for add/remove keys - not supporting migration here
guard let userInfo = notification.userInfo as? [String: [NSPersistentStore]] else {
unhandledError("Invalid userInfo for NSPersistentStoreCoordinatorStoresDidChange.") }
userInfo[NSAddedPersistentStoresKey]?.forEach { self.didAddStore([=10=]) }
userInfo[NSRemovedPersistentStoresKey]?.forEach { self.didRemoveStore([=10=]) }
}
}
deinit {
NotificationCenter.default
.removeObserver(self, name: .NSPersistentStoreCoordinatorStoresDidChange, object: self)
}
private func didAddStore(_ store: NSPersistentStore) {
guard store.isReadOnly else { return }
var addedObjects = Set<NSManagedObjectID>()
baseEntityNames.forEach { entityName in
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: entityName)
fetchRequest.affectedStores = [store]
do {
let addedEntityObjects = try readOnlyTestContext.fetch(fetchRequest)
addedObjects = addedObjects.union(addedEntityObjects.map { [=10=].objectID })
} catch {
unhandledError("Failed to fetch all \(entityName) for read only check: \(error)") }
}
readOnlyObjects[store.identifier] = addedObjects
}
private func didRemoveStore(_ store: NSPersistentStore) {
guard store.isReadOnly else { return }
readOnlyObjects.removeValue(forKey: store.identifier)
}
/// Returns the minimum set of entities that can be fetched for readonly checking
private lazy var baseEntityNames: [String] = {
return managedObjectModel.entitiesByName.compactMap { .superentity == nil ? [=10=] : nil }
}()
private var readOnlyTestContext: NSManagedObjectContext
/// Readonly objectIDs keyed per persistent store
private var readOnlyObjects = [String : Set<NSManagedObjectID>]()
internal func isObjectReadOnly(_ objectID: NSManagedObjectID) -> Bool {
return readOnlyObjects.contains(where: { .contains(objectID) } )
}
}
然后我向 NSManagedObject
添加了一个扩展,以查询其 NSPersistentStoreCoordinator
的只读状态:
public extension NSManagedObject
{
/// Does this managed object reside in a read-only persistent store?
var isReadOnly: Bool {
guard let coordinator = managedObjectContext?
.persistentStoreCoordinator as? GraphStoreCoordinator else {
unhandledError("Should only check readonly status in a GraphStoreCoordinator") }
return coordinator.isObjectReadOnly(objectID)
}
}