2012-09-14 53 views
8

閱讀幾十個類似的問題,我想先從這個說法:「我沒設置NSFetchedResultsController的代表,它沒有工作。」 。NSFetchedResultsController沒有看到新的插入/刪除更新後讀取值

所以我有一個簡單的TableViewController其細胞充滿NSFetchedResultsController。這裏的FRC初始化代碼:

@property (strong, nonatomic) NSFetchedResultsController *frc; 

... 

- (NSFetchedResultsController *)frc 
{ 
    if (!_frc) 
    { 
     NSError *error = nil; 
     NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:e_product]; 
     request.sortDescriptors = [NSArray arrayWithObjects: 
           [NSSortDescriptor sortDescriptorWithKey:@"product_group.product_group_name" ascending:YES], 
           [NSSortDescriptor sortDescriptorWithKey:f_product_name ascending:YES], 
           nil]; 
     _frc = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[DTGGlobalSettings sharedInstance].moc sectionNameKeyPath:@"product_group.product_group_name" cacheName:nil]; 
     _frc.delegate = self; 
     [_frc performFetch:&error]; 
     if (error) 
     { 
      NSLog(@"Error while fetching products: %@!", error.userInfo); 
     } 
    } 

    return _frc; 
} 

我也有一些調試標籤實現NSFetchedResultsController委託方法:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates. 
    NSLog(@"controllerWillChangeContent"); 
    [self.tableView beginUpdates]; 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 

    UITableView *tableView = self.tableView; 

switch(type) { 

    case NSFetchedResultsChangeInsert: 
     NSLog(@"didChangeObject - insert"); 
     [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeDelete: 
     NSLog(@"didChangeObject - delete"); 
     [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeUpdate: 
     NSLog(@"didChangeObject - update"); 
     [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
     break; 

    case NSFetchedResultsChangeMove: 
     NSLog(@"didChangeObject - move"); 
     [tableView deleteRowsAtIndexPaths:[NSArray 
              arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     [tableView insertRowsAtIndexPaths:[NSArray 
              arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
} 
} 


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { 

switch(type) { 

    case NSFetchedResultsChangeInsert: 
     NSLog(@"didChangeSection - insert"); 
     [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 

    case NSFetchedResultsChangeDelete: 
     NSLog(@"didChangeSection - delete"); 
     [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; 
     break; 
} 
} 


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
// The fetch controller has sent all current change notifications, so tell the table view to process all updates. 
NSLog(@"controllerDidChangeContent"); 
[self.tableView endUpdates]; 
} 

在我的導航欄我有刷新按鈕,它的功能是火起來的產品目錄方法誰執行以下操作:1. 產品獲取遠程MySQL服務器 2.如果有標識的產品不存在 - 創建並填充 3.如果它存在於所有領域,所有的字段根據更新取值爲

在第2行和第3行之後,商店被保存。 我對應用程序中的所有CoreData操作使用單個NSManagedObjectContext。

當我開始首次應用,TVC是空的,因爲沒有產品取呢。當我按Refresh時,新產品被提取並插入到ManagedObjectContext中,但NSManagedObjectContext沒有看到/聽到任何更改:沒有委託方法被調用,因此沒有新行被添加到TVC。 當我重新啓動應用程序時,新產品已到位,並且沒有任何問題進入TVC。

如果我再次按下刷新按鈕的時候有一些產品出現,很短的延遲之後便全部消失。一些調試告訴我,如果在更新實體的字段(實際值相同)並保存商店後發生。這次的委託方法像魅力一樣工作,對於每個更新和保存的實體控制器:didChangeObject:atIndexPath:forChangeType:使用forChangeType = NSFetchedResultsChangeDelete調用newIndexPath。

問題1:爲什麼NSFetchedResultsController沒有看到插入的實體,而不應用程序重新啓動? 問題2:爲什麼NSFetchedResultsController將已獲取的實體標記爲「不存在」(?),並在存儲保存後將它們從TVC中刪除?

我希望得到任何幫助和想法,是這個問題的整個上週的戰鬥;(

UPD1(對喬迪): 這裏有一些細節我使用自定義的類DTGGlobalSettings分享一些增值經銷商。 。在整個應用程序,就是我初始化其sharedInstance屬性:

+(DTGGlobalSettings *)sharedInstance 
{ 
    static DTGGlobalSettings *myInstance = nil; 

    if (nil == myInstance) 
    { 
     myInstance = [[[self class] alloc] init]; 
     // set values here 
     // try to acces MOC to init CoreData 
     [myInstance moc];   
     myInstance.baseURL = @"http://local.app/"; 
} 
return myInstance; 
} 

至Init,CoreData堆棧我用蘋果文檔的例子,因爲某種原因,我沒有看到勾選「使用CoreData」創建一個新的時項目,我確信我以前在Xc看過它頌歌,但現在我不知道;((的Xcode 4.4.1):

#pragma mark Core Data stack 

- (NSManagedObjectContext *) moc { 

if (_moc != nil) { 
    return _moc; 
} 
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
if (coordinator != nil) { 
    _moc = [[NSManagedObjectContext alloc] init]; 
    [_moc setPersistentStoreCoordinator: coordinator]; 
} 
return _moc; 
} 


- (NSManagedObjectModel *)managedObjectModel { 

if (_managedObjectModel != nil) { 
    return _managedObjectModel; 
} 
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];  
return _managedObjectModel; 
} 


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 

if (_persistentStoreCoordinator != nil) { 
    return _persistentStoreCoordinator; 
} 
NSURL *storeUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
storeUrl = [storeUrl URLByAppendingPathComponent:DOC_NAME]; 

NSError *error; 
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]]; 

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) { 
    NSLog(@"Error adding a store to the coordinator: %@, %@", error, error.userInfo); 
}   
return _persistentStoreCoordinator; 
} 

-(void)saveDataStore 
{ 
    NSError *error; 
    if (![self.moc save:&error]) NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
} 

的 'MOC'(ManagedObjectContext)DTGGlobalSettings的屬性然後使用無處不在的應用,在那裏我需要訪問CoreData。

現在到第二部分,更新數據庫。我從遠程Web服務器獲取JSON格式的新實體,瀏覽結果字典併爲請求結果中找到的每個實體調用createFromDictionary方法。下面的代碼:

+(Product *)createFromDictionary:(NSDictionary *)entityData inContext:(NSManagedObjectContext *)moc performUpdate:(BOOL)update 
{ 
Product *result; 
if (update) 
{ 
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:e_product]; 
    request.predicate = [NSPredicate predicateWithFormat:@"%K = %@", f_product_id, [entityData objectForKey:f_product_id]]; 
    result = [[DTGGlobalSettings sharedInstance].moc executeFetchRequest:request error:nil].lastObject; 
    if (!result) 
    { 
     NSLog(@"Error updating Product ID %@! Cannot fetch entity.", [entityData objectForKey:f_product_id]); 
     return nil; 
    } 
} else 
{ 
    result = [NSEntityDescription insertNewObjectForEntityForName:e_product inManagedObjectContext:[DTGGlobalSettings sharedInstance].moc]; 
} 

result.product_id = [[DTGGlobalSettings sharedInstance].numFormatter numberFromString:[entityData objectForKey:f_product_id]]; 
result.product_image = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[DTGGlobalSettings sharedInstance].baseURL stringByAppendingString:[entityData objectForKey:f_product_image]]]]; 
result.product_name = [entityData objectForKey:f_product_name]; 

return result; 
} 

當我用完fethed實體的,我稱之爲[DTGGlobalSettings sharedInstance] saveDataStore(見上文)。此時TVC中的現有行(如果有的話)消失。如果我添加了一些新的實體,保存時就不會發生任何事情,即TVC不會更新它的行。

+0

您發佈了錯誤的代碼。有趣的是如何將數據導入數據庫,以及如何爲導入和讀取結果控制器設置核心數據堆棧。 –

+0

我在UPD1中添加了一些你所要求的細節。我希望現在更清楚我是如何以此結束的...... – Arseniy

+0

關於更新的任何想法? – Arseniy

回答

14

其實,我認爲你的第一個編輯前的帖子有所有必要的信息。我只是沒有讀過它(我不喜歡不停地滾動讀取長長的代碼行,有時候就是不這樣做 - 我的糟糕)。

您的問題似乎與您的FRC排序描述符有關。

FRC不能很好地處理關係排序描述符的更新。

有人認爲它是如何設計的。我認爲這是一個錯誤。

看到這篇文章Changing a managed object property doesn't trigger NSFetchedResultsController to update the table view我的需要。希望你會看到你的案例的相似之處。

+0

太棒了!我只是很快刪除排序描述符和節名稱路徑,它的工作!我永遠不會猜測這是這樣的作品;)謝謝! – Arseniy

+0

這個問題還在嗎? –

+0

是的。 https://insanitysauce.files.wordpress.com/2013/09/bsxgx3vciaax5g5.jpg –

1

我剛剛花時間處理同一問題,發現以下情況:當sectionNameKeyPath引用的關係字段值可能爲nil值時,FRC更新在插入對象時不起作用。

這可能與Xcode控制檯中的警告有關,表示將爲該字段設置爲nil的對象創建該部分。我想這部分與FRC的內部工作混淆起來。

相關問題