我在UICollectionView中使用NSFetchedResultsController。後臺上下文保存導致NSFetchedResultsController didChange anObject調用.delete而不是.update
問題:當用戶打開視圖時,我向API發送一個請求,並使用performBackgroundTask()
解析背景中的響應。 NSFetchedResultsController將正確加載託管對象,但是在我解析數據並調用context.save()
後,將使用NSFetchedResultsChangeType.delete
調用didChangeObject
方法,但在此之後既不會調用update
也不會調用insert
。
這是一些代碼。
解析和保存
static func parse(withJSON json: [JSON]) {
let container = (UIApplication.shared.delegate as! AppDelegate).persistentContainer
container.performBackgroundTask() { (context) in
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
for feedJSON in json {
if let feedID = feedJSON["_id"].string {
let feed = Feed.getWithId(id: feedID, withContext: context) ?? (NSEntityDescription.insertNewObject(forEntityName: "Feed", into: context) as! Feed)
feed.update(withJSON: feedJSON, withContext: context)
}
}
do {
try context.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
}
視圖背景
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "TheApp")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
#if DEVELOPMENT
fatalError("Unresolved error \(error), \(error.userInfo)")
#endif
}
})
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.retainsRegisteredObjects = true
return container
}()
初始化NSFetchedResultsController
func initializeFetchedResultsController() {
guard let user = Current.user else {
return
}
let request: NSFetchRequest<Feed> = Feed.fetchRequest()
let createdAtSort = NSSortDescriptor(key: "createdAt", ascending: false)
request.sortDescriptors = [createdAtSort]
request.predicate = NSPredicate(format: "author = %@", user)
let moc = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
resourceFetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)
resourceFetchedResultsController?.delegate = self
do {
try resourceFetchedResultsController?.performFetch()
} catch {
fatalError("Failed to initialize FetchedResultsController: \(error)")
}
}
author
與管理對象User
是一對一的關係。我已經驗證過,在保存背景上下文時不會以某種方式刪除它。我還將Feed.author關係的刪除規則更改爲No Action
,Nullify
和Cascade
,但沒有任何更改。
對象更改通知
最後,我設置的通知聽在環境的變化。它在performBackgroundTask()
中的每個context.save()
之後成功調用,但它只有關於正在更新的對象的信息,並且從不刪除。
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectContextObjectsDidChange), name: NSNotification.Name.NSManagedObjectContextObjectsDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectContextObjectsDidChange), name: NSNotification.Name.NSManagedObjectContextWillSave, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(managedObjectContextObjectsDidChange), name: NSNotification.Name.NSManagedObjectContextDidSave
是沒有工作的一個事情...
當我改變從NSPredicate(format: "author = %@", user)
謂詞NSPredicate(format: "title = %@", 'My Title')
它會正常工作。當然,這隻適用於具有該標題的一個對象,但它會成功保存上下文,合併更改並按照我的預期更新集合。
當您檢查已更新的對象時,'author'屬性的值是多少?如果它不是'Current.user',FRC將觸發刪除委託調用:由於對象不再與謂詞相匹配,因此必須刪除相應的collectionView單元格。 – pbasdf
是的,我也想到了,但更新後,作者對象仍然是'Current.user' – Sonny