iphone – 在獲取PantantID之後,核心資料無法充滿物件的錯誤
我從網路伺服器獲取資料,在一個名為backgroundMOC的子私人背景上下文中處理它.它是一個與主UI相關聯的mainMOC的子程序,因此在backgroundMOC上儲存觸發UI更改. mainMOC是一個masterMOC的子代,它是一個與持久儲存相關聯的私有後臺佇列,所以儲存在主節點上儲存到磁碟.
我現在所做的是接收資料,在backgroundMOC上建立新物件,然後儲存backgroundMOC(以便UI更新),儲存mainMOC(使我幾乎可以儲存到磁碟),並儲存masterMOC(以便我可以最終寫入磁碟).問題是當物件通過獲取的結果控制器出現在UI中時,objectId仍然是暫時的.
這會導致重複行問題,如果我從伺服器收到相同的資料(意外),我的backgroundMOC不知道這個物件已經存在,因為它沒有被分配一個永久的id,所以它建立另一個物件.當我重新啟動應用程式時,重複的物件消失,所以我知道這只是一個id對映的問題.
所以我以為我可以試試
[backgroundMOC obtainPermanentIDsForObjects:backgroundMOC.registeredObjects.allObjects error:nil];
在儲存之前(我也儲存後嘗試過).但是,由於某種原因,呼叫此行會丟擲異常:
CoreData could not fulfill a fault for...
如果您有任何提示可能導致我正確的方向,請分享.謝謝
編輯:好的,最初我在backgroundMOC上呼叫getsPermanentIDsForObjects,它是mainMOC的一個小孩,它是masterMOC的一個子代.我切換它,以便在mainMOC上獲得ids,並解決了我所有的問題(現在).我從來不會在child context上呼叫getsPermIds嗎?
這是一個已知的錯誤(巢狀的上下文在儲存新物件時不會獲得永久性的ID)可能會在即將釋出的版本中被修復
你應該可以要求永久性的ID,但你應該只是要求他們已經插入的物件.
[moc obtainPermanentIDsForObjects:moc.insertedObjects.allObjects error:0];
您必須在儲存MOC之前執行此操作,因為如果在不獲取永久ID的情況下儲存,則臨時ID將傳播到父上下文.例如,在您儲存到mainMoc的情況下,然後獲取IDS,backgroundMOC仍然具有臨時ID,因此從未來的儲存將建立重複的資料.
請注意,獲取永久ID一直到資料庫,但是如果您在主MOC的MOC中執行此操作,則在發生這種情況時,您不應該阻止主執行緒.
所以,在你的最低級別的MOC中,你應該有效地擁有這樣的東西(當然有適當的錯誤處理)…
[backgroundMoc performBlock:^{ [backgroundMoc obtainPermanentIDsForObjects:backgroundMoc.insertedObjects.allObjects error:0]; [backgroundMoc save:0]; [mainMoc performBlock:^{ [mainMoc save:0]; [masterMoc performBlock:^{ [masterMoc save:0]; }]; }]; }];
還有一些其他可以玩的遊戲,如果你願意的話.
提供類似於NSManagedObject的類別…
@implementation NSManagedObject (initWithPermanentID) - (id)initWithEntity:(NSEntityDescription *)entity insertWithPermanentIDIntoManagedObjectContext:(NSManagedObjectContext *)context { if (self = [self initWithEntity:entity insertIntoManagedObjectContext:context]) { NSError *error = nil; if (![context obtainPermanentIDsForObjects:@[self] error:&error]) { @throw [NSException exceptionWithName:@"CoreData Error" reason:error.localizedDescription userInfo:error.userInfo]; } } return self; } + (NSArray*)createMultipleObjects:(NSUInteger)count withEntity:(NSEntityDescription *)entity inManagedObjectContext:(NSManagedObjectContext *)context { NSMutableArray *array = [NSMutableArray arrayWithCapacity:count]; for (NSUInteger i = 0; i < count; ++i) { [array addObject:[[self alloc] initWithEntity:entity insertIntoManagedObjectContext:context]]; } NSError *error = nil; if (![context obtainPermanentIDsForObjects:array error:&error]) { @throw [NSException exceptionWithName:@"CoreData Error" reason:error.localizedDescription userInfo:error.userInfo]; } return array; } @end
現在,在第一個,你正在付錢進入資料庫,併為每個建立的實體建立一個ID,但是並不是那麼多,而是發生在一個後臺執行緒中,每個下降都很短
哦,這不是最好的,但它提供了有用的.此外,第二個建立相同物件的多個,並同時抓取它們的永久ID.
您還可以使用直接連線到PSC的MOC,並觀察DidChange事件,但是與舊方式相同.
不幸的是,你不能有一個單獨的MOC只是做出持久化ID請求並傳遞ObjectID,雖然你可以有一個單獨的MOC在DB中建立原型物件,並給你的ObjectID.
一個原型工廠是一個相當普遍的模式,如果你走這條路線,當最終的錯誤修復到這裡時,很容易做一個小的改變.
編輯
響應斯文
如果您正在建立新的複雜圖形,則需要在建立後立即獲取永久性ID.要減少對商店的命中次數,您應該全部建立它們,然後一次獲取ID,然後開始掛起它們.
老實說,所有這一切都是為了解決目前存在的錯誤,這些bug值得為小型到中型的更新而努力.當錯誤被修復時,您的程式碼將是一樣的(無需獲取).所以,我建議這種方法進行較小的進口.
如果您正在進行大規模更新,建議您使用“舊”方法.建立一個直接連線到PSC的MOC.在那裡進行所有的更改,並讓您的“活”上下文只是從那些DidSave通知合併.
最後,對資料庫的永久ID影響.丟棄MOC是可以的.磁碟被擊中,元資料被更改,但物件不被保留.
老實說,我沒有做一個大的考驗,看看是否有空的空間,但是,所以你可能想這樣做,並與我一起回來.
檢視磁碟上的實際資料庫檔案大小,然後建立10000個物件,然後獲取永續性ID,釋放MOC,再次檢視大小.
如果有影響,您可以嘗試刪除物件,或者在大型更新後在資料庫上執行真空,以檢視是否有效.
如果要建立很多可能會丟棄的物件,那麼就不需要打資料庫了.您可能只想直接附加到PSC並使用舊的忠實通知.
http://stackoverflow.com/questions/11321717/core-data-could-not-fullfil-fault-for-object-after-obtainpermanantids