我有一個非常令人沮喪的問題,我想幫助理解甚至修復。iOS核心數據「樂觀鎖定失敗」
我正在通過構建一個相當簡單的應用程序來學習Core Data。
我的模型如下:
用戶
屬性
- 名
- 性別
- DOB
關係
hasCompletedItem -
isInAgeGroup 「用戶可以完成許多列表項,列表項可以由許多用戶完成」 - 「用戶是一個AgeGroup,一AgeGroup可以包含多個用戶」
AgeGroup
屬性
- 標題
關係
hasItems - 「一個AgeGroup有許多與其相關的listItems中,一個ListItem只能與一個AgeGroup相關「
個
hasUsers - 「一個AgeGroup具有與之相關的許多用戶,用戶可以僅在1個AgeGroup」
的ListItem
屬性
- itemText
個關係
completedByUser - 「列表項可以由多個用戶完成,用戶可以完成許多列表項」。
forAgeGroup - 「列表項被分配到一個單一的AgeGroup,一個AgeGroup可以有多個listItems中的」
我的程序設置如下:
- 的AppDelegate中處理創建CoreData堆棧。
- didFinishLaunchingWithOptions訪問MenuViewController並穿過managedObjectContext爲它的使用方法:
id navigationController = [[self window] rootViewController];
id controller = [navigationController topViewController];
[controller setManagedObjectContext:[self managedObjectContext]];
- 的MenuViewController顯示器。它是一個帶有幾個按鈕的UIViewController,每個按鈕都會延伸到其他視圖控制器。
- 當按下上MenuViewController的 '開始' 按鈕,現有managedObjectContext在prepareForSegue方法傳遞:然後
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"selectprofile"]) {
[[segue destinationViewController] setManagedObjectContext:[self managedObjectContext]];
}
}
- 的SelectProfileTableViewController被示出。它列出每個用戶的表格。它有一個允許添加新用戶的按鈕。 tableview的數據由NSFetchedResultsController提供,它基本上只提取用戶實體中的所有記錄。
- 攻 「添加」 按鈕,將加載AddProfileViewController而不是通過對managedObjectContext前:
AddProfileViewController *viewController = (AddProfileViewController *)[[segue destinationViewController] topViewController];
[viewController setManagedObjectContext:self.managedObjectContext];
- 的AddProfileViewController僅僅是一個UIViewController。它具有名稱的文本字段,D.O.B等。
- 它有一個方法addProfileDone,當用戶點擊「完成」按鈕時被調用。在該方法中,創建新的用戶managedObject及其屬性被設置:
User *newMO = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:_managedObjectContext];
newMO.name = self.nameTextField.text;
newMO.dob = _dob;
// etc
- 接下來,它也試圖設置這個新的用戶實體之間的關係,它的相應的AgeGroup實體。
NSFetchRequest *ageGroupRecordRequest = [NSFetchRequest fetchRequestWithEntityName:@"AgeGroup"];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"title"
ascending:YES];
[ageGroupRecordRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
// Make a predicate to find the correct AgeGroup based on what was calculated
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(title == %@)", ageGroup];
[ageGroupRecordRequest setPredicate:predicate];
// Run the fetch request, should only ever get 1 result back.
NSError *fetchError;
// Result will be an array with a single AgeGroup entity
NSArray *fetchedObjects = [_managedObjectContext executeFetchRequest:ageGroupRecordRequest error:&fetchError];
// Set up the relationship using the fetched entity
// Crashes when saving if below line is uncommented
newMO.isInAgeGroup = fetchedObjects[0];
如上代碼注意到,當行則取消註釋和managedObjectContext去救人,我得到以下錯誤:
CoreData:錯誤:未能解決持樂觀態度鎖定失敗:樂觀鎖定失敗(null) CoreData:錯誤:無法解決樂觀鎖定失敗。舊的保存請求是:{inserts(( 「0x942dd40」 )),updates(( 「0x8e4ed60」 )),deletes()locks()} 2014-04-12 20:00:09。482 ChekList [6076:60b] CoreData:錯誤:未能解決樂觀鎖定失敗。下一次嘗試將是:{插入物(( 「0x942dd40」 )),更新(( 「0x8e4ed60」 )),刪除()鎖()} SQL:BEGIN EXCLUSIVE 註釋:獲得最大峯爲ENTITYID = 3 註釋:使用old = 4017和new = 4018更新entityID = 3的最大pk值sql:COMMIT sql:BEGIN EXCLUSIVE sql:UPDATE ZAGEGROUP SET Z_OPT =?哪裏Z_PK =? AND(Z_OPT =?OR Z_OPT IS NULL) details:SQLite bind [0] =(int64)1 詳細信息:SQLite bind [1] =(int64)6 詳細信息:SQLite bind [2] = nil sql:ROLLBACK SQL:SELECT Z_PK,Z_OPT FROM ZAGEGROUP WHERE Z_PK(6)ORDER BY Z_PK 註釋:SQL執行時間:0.0006s
我的理解是,基本上別的東西已經修改了背景,並且在保存CoreData已經注意到這一點,並停止。我已閱讀關於更改ManagedObjectContext上的MergePolicy,但我不想知道爲什麼必須這樣做。
有趣的是,如果我註釋掉試圖設置關係的線條,它可以正常工作。 (當然關係沒有設置)
據我可以看到,我正確地將managedObjectContext傳遞給每個視圖控制器。我還確保沒有多個上下文訪問相同的持久性存儲。
是否有可能是之前由於某種原因正在修改上下文的View Controller中的FetchedResultsController?
是否有人能夠提供一些信息和可能的解決方案?我寧願不必更改合併策略。我看不出爲什麼我不得不考慮它的一個相當簡單的例子。在這一天的大部分時間裏,我一直在拉我的頭髮。
我不禁想到這很可能是我錯過的簡單東西。
謝謝, Brett。
發現這不是一個解決方案。問題在於,在將對象添加到該表的其他非反身關係之前,需要保存我的反身關係。 –