gpt4 book ai didi

ios - 核心数据 : Get notified when NSManagedObject is changed without keeping reference to NSManagedObject

转载 作者:行者123 更新时间:2023-11-28 21:09:41 24 4
gpt4 key购买 nike

我想观察特定 NSManagedObject 的变化并相应地更新 UI。

不想保留对NSManagedObject 的引用,因为它可能随时被删除(即通过远程推送通知的结果)。

目前我正在设置 NSFetchRequestNSFetchedResultsControllerNSFetchedResultsControllerDelegate 来实现这一点。但是想简化这个解决方案(见下文)。

有没有什么简单的方法可以在不使用 NSFetchedResultsControllerDelegate 的情况下观察 NSManagedObject 的变化?

谢谢!

示例代码(Xcode Playground )

import PlaygroundSupport
import Cocoa
import CoreData

PlaygroundPage.current.needsIndefiniteExecution = true

extension NSManagedObject {

public static var entityName: String {
let className = String(describing: self)
return className.components(separatedBy: ".").last!
}

public convenience init(in context: NSManagedObjectContext) throws {
let entityName = type(of: self).entityName
guard let entityDescription = NSEntityDescription.entity(forEntityName: entityName, in: context) else {
fatalError()
}
self.init(entity: entityDescription, insertInto: context)
}
}

@objc(UserInfoEntity)
class UserInfoEntity: NSManagedObject {

@NSManaged var id: Int64
@NSManaged var name: String

convenience init(id: Int64, name: String, in context: NSManagedObjectContext) throws {
try self.init(in: context)
self.id = id
self.name = name
}
}

class DBStack {

static let shared = DBStack()
static var mainContext: NSManagedObjectContext {
return shared.mainContext
}

private typealias PSC = NSPersistentStoreCoordinator
private lazy var coordinator: PSC = PSC(managedObjectModel: self.model)
private lazy var model: NSManagedObjectModel = self.setupModel()
private lazy var writerContext: NSManagedObjectContext = self.setupWriterContext()
private lazy var mainContext: NSManagedObjectContext = self.setupMainContext()
private var isInitialized = false

init() {
}

func setupInMemoryStore() throws {
guard !isInitialized else { return }
isInitialized = true
try coordinator.addPersistentStore(ofType: NSInMemoryStoreType,
configurationName: nil, at: nil, options: nil)
}

static func makeChildContext() -> NSManagedObjectContext {
let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
moc.parent = mainContext
return moc
}

private func setupWriterContext() -> NSManagedObjectContext {
let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
moc.persistentStoreCoordinator = coordinator
return moc
}

private func setupMainContext() -> NSManagedObjectContext {
let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
moc.parent = writerContext
return moc
}

private func setupModel() -> NSManagedObjectModel {

let attributeID = NSAttributeDescription()
attributeID.name = "id"
attributeID.attributeType = .integer64AttributeType
attributeID.isOptional = false
attributeID.isIndexed = true

let attributeName = NSAttributeDescription()
attributeName.name = "name"
attributeName.attributeType = .stringAttributeType
attributeName.isOptional = false

let entityUserInfo = NSEntityDescription()
entityUserInfo.name = "UserInfoEntity"
entityUserInfo.managedObjectClassName = "UserInfoEntity"
entityUserInfo.properties = [attributeID, attributeName]

let model = NSManagedObjectModel()
model.entities = [entityUserInfo]
return model
}
}

class FetchedResultsDelegate: NSObject, NSFetchedResultsControllerDelegate {

public var entityChanged: ((Void) -> Void)?

public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
entityChanged?() // Notify about content change.
}
}

// Create or Update user info.
func updateUserInfo(id: Int64, name: String) {
let privateContext = DBStack.makeChildContext()
privateContext.perform {
let request: NSFetchRequest<UserInfoEntity> = NSFetchRequest(entityName: UserInfoEntity.entityName)
request.predicate = NSPredicate(format: "%K == %@", argumentArray: [#keyPath(UserInfoEntity.id), id])
request.fetchLimit = 1
do {
if let userInfo = try privateContext.fetch(request).first {
userInfo.name = name
} else {
_ = try UserInfoEntity(id: id, name: name, in: privateContext)
}
if privateContext.hasChanges {
print("→ Will save userInfo. Name: " + name)
try privateContext.save()
}
} catch {
print(error)
}
}
}

let stack = DBStack()
try stack.setupInMemoryStore()
let userID: Int64 = 1
let request: NSFetchRequest<UserInfoEntity> = NSFetchRequest(entityName: UserInfoEntity.entityName)
request.predicate = NSPredicate(format: "%K == %@", argumentArray: [#keyPath(UserInfoEntity.id), userID])
request.sortDescriptors = [NSSortDescriptor(key: #keyPath(UserInfoEntity.name), ascending: false)]
let delegate = FetchedResultsDelegate()
let fetchedResultsController: NSFetchedResultsController<UserInfoEntity>
= NSFetchedResultsController(fetchRequest: request, managedObjectContext: DBStack.mainContext,
sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = delegate

// Here is our event handler. Called on main thread.
delegate.entityChanged = { [weak fetchedResultsController] in
let userInfo = fetchedResultsController?.fetchedObjects?.first
print("! UserInfo changed: \(String(describing: userInfo?.name))")
// Update UI.
}

try fetchedResultsController.performFetch()

DispatchQueue.global().async {
updateUserInfo(id: userID, name: "Alex")
updateUserInfo(id: userID, name: "Alexander")
}

将打印:

→ Will save userInfo. Name: Alex
! UserInfo changed: Optional("Alex")
→ Will save userInfo. Name: Alexander
! UserInfo changed: Optional("Alexander")

最佳答案

一种方法是:

  1. 保存要监视的托管对象的 objectID 属性的值,而不是对托管对象的引用。
  2. 使用 NotificationCenterNSManagedObjectContextObjectsDidChange 通知添加观察者,该通知由您的托管对象上下文生成。
  3. 当您收到此通知时,查看 userInfo 字典中名为 NSUpdatedObjectsKey 的键。它包含对任何已更改的托管对象的引用。查看其中是否有您在第 1 步中保存的 objectID

根据您希望事情如何工作,您可能更喜欢使用 NSManagedObjectContextDidSave 通知。您可能还想使用 NSInsertedObjectsKey 和/或 NSDeletedObjectsKey

关于ios - 核心数据 : Get notified when NSManagedObject is changed without keeping reference to NSManagedObject,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44101845/

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