我在使用帶有簡單一對一關係的NSFetchedResultsController插入時遇到了一些問題。當我創建一個新的Source對象時,它與Target對象具有一對一的關係,它似乎使用NSFetchedResultsChangeInsert和NSFetchedResultsChangeUpdate類型兩次調用 - [(void)controller:(NSFetchedResultsController *)controller didChangeObject ...]這會導致tableview在更新後立即顯示不準確的數據。NSFetchedResultsController更新和一對一關係問題
我可以用一個基於XCode在基於導航的CoreData應用程序中生成的標準模板項目的簡單示例重新創建此項目。該模板使用timeStamp屬性創建一個Event實體。我想爲這個事件添加一個新的實體「Tag」,它與Entity只是一對一的關係,這個想法是每個事件都有一些來自某個標籤列表的特定Tag。我在覈心數據編輯器中創建了事件到標籤的關係,以及從標籤到事件的反向關係。然後我產生NSManagedObject子類都事件和標籤,這是相當標準:
@interface Event : NSManagedObject {
@private
}
@property (nonatomic, retain) NSDate * timeStamp;
@property (nonatomic, retain) Tag * tag;
and
@interface Tag : NSManagedObject {
@private
}
@property (nonatomic, retain) NSString * tagName;
@property (nonatomic, retain) NSManagedObject * event;
我則預先填充的標籤實體與推出一些數據,這樣我們就可以從標籤插入時挑一個新的事件。在AppDelegate中,返回persistentStoreCoordinator之前調用此:
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Tag" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
//check if Tags haven't already been created. If not, then create them
if (fetchedObjects.count == 0) {
NSLog(@"create new objects for Tag");
Tag *newManagedObject1 = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:context];
newManagedObject1.tagName = @"Home";
Tag *newManagedObject2 = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:context];
newManagedObject2.tagName = @"Office";
Tag *newManagedObject3 = [NSEntityDescription insertNewObjectForEntityForName:@"Tag" inManagedObjectContext:context];
newManagedObject3.tagName = @"Shop";
}
[fetchRequest release];
if (![context save:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
現在,我改變了insertNewObject代碼添加標籤的事件屬性,我們要插入。我隨便挑從fetchedObjects的這個例子中,列表中的第一個:
- (void)insertNewObject
{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
Event *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
// If appropriate, configure the new managed object.
// Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
[newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityTag = [NSEntityDescription entityForName:@"Tag" inManagedObjectContext:context];
[fetchRequest setEntity:entityTag];
NSError *errorTag = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&errorTag];
if (fetchedObjects.count > 0) {
Tag *newtag = [fetchedObjects objectAtIndex:0];
newManagedObject.tag = newtag;
}
// Save the context.
NSError *error = nil;
if (![context save:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
我想現在看到的tableview中反映這些變化,所以我做了的UITableViewCell鍵入UITableViewCellStyleSubtitle,改變configureCell向我展示標記名詳細文本標籤:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
Event *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[managedObject valueForKey:@"timeStamp"] description];
cell.detailTextLabel.text = managedObject.tag.tagName;
}
現在一切都已到位。當我打電話insertNewObject,它似乎精細打造的第一行,但第二行是第一個重複的,即使時間戳應該是幾秒鐘間隔:
當我滾動屏幕上下它會刷新行,然後用正確的時間顯示正確的結果。當我遍歷代碼時,會出現核心問題:插入一個新行似乎是兩次調用[(NSFetchedResultsController *)controller didChangeObject ...],一次用於插入,一次用於更新。我不知道爲什麼更新被調用。這裏的重頭戲:如果我刪除事件和標記之間的相反關係,插入開始工作就好!只有插入被調用,行不重複,並且工作正常。
那麼,它是什麼導致NSFetchedResultsController委託方法被調用兩次的反向關係?我應該在這種情況下生活嗎?我知道如果沒有指定inverse,XCode會發出警告,這似乎是一個壞主意。我在這裏做錯了什麼?這是一個已知的解決方法的已知問題?
謝謝。
對此有何更新?我發現了一個類似的問題。我得到1個上下文更改通知,並且我提取的結果控制器委託被擊中兩次。 –