Vla*_*lad 1 macos core-data ios
我想观察特定的变化NSManagedObject并相应地更新 UI。
我不想保留引用,NSManagedObject因为它可能随时被删除(即通过远程推送通知的结果)。
目前我正在设置NSFetchRequest并实现这一目标NSFetchedResultsController。NSFetchedResultsControllerDelegate但想要简化这个解决方案(见下文)。
有没有什么简单的方法可以在NSManagedObject不使用 的情况下观察变化NSFetchedResultsControllerDelegate?
谢谢你!
\n\n示例代码 (Xcode Playground)\n
\n\nimport PlaygroundSupport\nimport Cocoa\nimport CoreData\n\nPlaygroundPage.current.needsIndefiniteExecution = true\n\nextension NSManagedObject {\n\n public static var entityName: String {\n let className = String(describing: self)\n return className.components(separatedBy: ".").last!\n }\n\n public convenience init(in context: NSManagedObjectContext) throws {\n let entityName = type(of: self).entityName\n guard let entityDescription = NSEntityDescription.entity(forEntityName: entityName, in: context) else {\n fatalError()\n }\n self.init(entity: entityDescription, insertInto: context)\n }\n}\n\n@objc(UserInfoEntity)\nclass UserInfoEntity: NSManagedObject {\n\n @NSManaged var id: Int64\n @NSManaged var name: String\n\n convenience init(id: Int64, name: String, in context: NSManagedObjectContext) throws {\n try self.init(in: context)\n self.id = id\n self.name = name\n }\n}\n\nclass DBStack {\n\n static let shared = DBStack()\n static var mainContext: NSManagedObjectContext {\n return shared.mainContext\n }\n\n private typealias PSC = NSPersistentStoreCoordinator\n private lazy var coordinator: PSC = PSC(managedObjectModel: self.model)\n private lazy var model: NSManagedObjectModel = self.setupModel()\n private lazy var writerContext: NSManagedObjectContext = self.setupWriterContext()\n private lazy var mainContext: NSManagedObjectContext = self.setupMainContext()\n private var isInitialized = false\n\n init() {\n }\n\n func setupInMemoryStore() throws {\n guard !isInitialized else { return }\n isInitialized = true\n try coordinator.addPersistentStore(ofType: NSInMemoryStoreType,\n configurationName: nil, at: nil, options: nil)\n }\n\n static func makeChildContext() -> NSManagedObjectContext {\n let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)\n moc.parent = mainContext\n return moc\n }\n\n private func setupWriterContext() -> NSManagedObjectContext {\n let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)\n moc.persistentStoreCoordinator = coordinator\n return moc\n }\n\n private func setupMainContext() -> NSManagedObjectContext {\n let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)\n moc.parent = writerContext\n return moc\n }\n\n private func setupModel() -> NSManagedObjectModel {\n\n let attributeID = NSAttributeDescription()\n attributeID.name = "id"\n attributeID.attributeType = .integer64AttributeType\n attributeID.isOptional = false\n attributeID.isIndexed = true\n\n let attributeName = NSAttributeDescription()\n attributeName.name = "name"\n attributeName.attributeType = .stringAttributeType\n attributeName.isOptional = false\n\n let entityUserInfo = NSEntityDescription()\n entityUserInfo.name = "UserInfoEntity"\n entityUserInfo.managedObjectClassName = "UserInfoEntity"\n entityUserInfo.properties = [attributeID, attributeName]\n\n let model = NSManagedObjectModel()\n model.entities = [entityUserInfo]\n return model\n }\n}\n\nclass FetchedResultsDelegate: NSObject, NSFetchedResultsControllerDelegate {\n\n public var entityChanged: ((Void) -> Void)?\n\n public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {\n entityChanged?() // Notify about content change.\n }\n}\n\n// Create or Update user info.\nfunc updateUserInfo(id: Int64, name: String) {\n let privateContext = DBStack.makeChildContext()\n privateContext.perform {\n let request: NSFetchRequest<UserInfoEntity> = NSFetchRequest(entityName: UserInfoEntity.entityName)\n request.predicate = NSPredicate(format: "%K == %@", argumentArray: [#keyPath(UserInfoEntity.id), id])\n request.fetchLimit = 1\n do {\n if let userInfo = try privateContext.fetch(request).first {\n userInfo.name = name\n } else {\n _ = try UserInfoEntity(id: id, name: name, in: privateContext)\n }\n if privateContext.hasChanges {\n print("\xe2\x86\x92 Will save userInfo. Name: " + name)\n try privateContext.save()\n }\n } catch {\n print(error)\n }\n }\n}\n\nlet stack = DBStack()\ntry stack.setupInMemoryStore()\nlet userID: Int64 = 1\nlet request: NSFetchRequest<UserInfoEntity> = NSFetchRequest(entityName: UserInfoEntity.entityName)\nrequest.predicate = NSPredicate(format: "%K == %@", argumentArray: [#keyPath(UserInfoEntity.id), userID])\nrequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(UserInfoEntity.name), ascending: false)]\nlet delegate = FetchedResultsDelegate()\nlet fetchedResultsController: NSFetchedResultsController<UserInfoEntity>\n = NSFetchedResultsController(fetchRequest: request, managedObjectContext: DBStack.mainContext,\n sectionNameKeyPath: nil, cacheName: nil)\nfetchedResultsController.delegate = delegate\n\n// Here is our event handler. Called on main thread.\ndelegate.entityChanged = { [weak fetchedResultsController] in\n let userInfo = fetchedResultsController?.fetchedObjects?.first\n print("! UserInfo changed: \\(String(describing: userInfo?.name))")\n // Update UI.\n}\n\ntry fetchedResultsController.performFetch()\n\nDispatchQueue.global().async {\n updateUserInfo(id: userID, name: "Alex")\n updateUserInfo(id: userID, name: "Alexander")\n}\nRun Code Online (Sandbox Code Playgroud)\n\n将打印:
\n\n\xe2\x86\x92 Will save userInfo. Name: Alex\n! UserInfo changed: Optional("Alex")\n\xe2\x86\x92 Will save userInfo. Name: Alexander\n! UserInfo changed: Optional("Alexander")\nRun Code Online (Sandbox Code Playgroud)\n
一种方法是:
objectID保存要监视的托管对象的属性值,而不是对托管对象的引用。NotificationCenter添加通知的观察者NSManagedObjectContextObjectsDidChange,该通知由托管对象上下文生成。userInfo字典中查找名为 的键NSUpdatedObjectsKey。它包含对任何已更改的托管对象的引用。查看其中是否有objectID您在步骤 1 中保存的内容。根据您希望事情如何运作,您可能NSManagedObjectContextDidSave更喜欢使用通知。您可能还想使用NSInsertedObjectsKey和/或NSDeletedObjectsKey。
| 归档时间: |
|
| 查看次数: |
2715 次 |
| 最近记录: |