2014-08-31 24 views
2

我在使用NSFetchedResultsControllersortDescriptors來請求填充表中有很多結果的表。我注意到,如果發生的變化將表格底部附近的一行移動到頂部,則didChangeObject:atIndexPath:forChangeType:newIndexPath:根本不會被調用。NSFetchedResultsController並不總是調用didChangeObject:atIndexPath:forChangeType:newIndexPath:NSFetchedResultsChangeMove

奇怪的是,我可以通過所有獲取的對象迭代,並調用performFetch後立即訪問他們的任何屬性解決這個問題。

什麼的問題可能是,或者這只是一個不起眼的蘋果的bug任何提示嗎?

這裏是我的代碼:

NSManagedObjectContext *context = [self managedObjectContext]; 
NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
request.entity = [NSEntityDescription entityForName:@"MyObject" inManagedObjectContext:context]; 
request.sortDescriptors = @[NSSortDescriptor sortDescriptorWithKey:@"order" ascending:NO]]; 
request.fetchBatchSize = 20; 
NSFetchedResultsController *fetched = [[NSFetchedResultsController alloc] 
             initWithFetchRequest:request 
             managedObjectContext:context 
             sectionNameKeyPath:nil 
                cacheName:nil]; 
fetched.delegate = self; 
NSError *error = nil; 
if (![fetched performFetch:&error]) { 
    NSLog(@"Unresolved error fetching objects: %@", error); 
} 

// Should not be necessary, but objects near the bottom won't move to the top without it. 
for (MyObject *o in fetched.fetchedObjects) { 
    o.someAttribute; 
} 

更新2014年9月12日:

我節省在後臺管理對象範圍內的所有數據,並且它似乎與我的問題看到。這是我的代碼,用於合併主要對象上下文中的更改:

+(void)initSaveListener { 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) 
               name:NSManagedObjectContextDidSaveNotification 
               object:[self privateContext]]; 
} 

+(void)mergeChanges:(NSNotification*)notification { 
    NSManagedObjectContext *context = [self mainContext]; 

    [context performBlock:^{ 
     [context mergeChangesFromContextDidSaveNotification:notification]; 
     NSError *error = nil; 
     if (![context save:&error]) { 
      NSLog(@"error merging changes %@, %@", error, [error userInfo]); 
     } 
    }]; 
} 
+0

是什麼導致此舉?根據您的描述,聽起來好像表格視圖中發生了變化(即用戶正在移動一行) – quellish 2014-08-31 06:00:40

+0

用戶操作不會導致它移動。這個變化發生在服務器上,並被流式傳輸到客戶端,並在核心數據中更新。這部分工作正常,並且在表視圖上調用reloadData會顯示正確的順序。 – ninjudd 2014-09-08 17:02:57

+0

是核心數據變化發生在'[self managedObjectContext]',父上下文還是子上下文描述的上下文中? – quellish 2014-09-08 18:28:09

回答

2

事實證明,此問題是由於使用NSManagedObjectContextDidSaveNotification從另一個上下文傳播對managedObjectContext的更改而引起的。本博客文章詳細解釋了爲什麼這會導致一個問題NSFetchedResultsController,以及如何解決它:

http://www.mlsite.net/blog/?p=518

這是在我上面的代碼方面的特殊修復:

+(void)mergeChanges:(NSNotification*)notification { 
    NSManagedObjectContext *context = [self mainContext]; 

    // Fault all objects that have changed so that NSFetchedResultsController will see the changes. 
    NSArray *objects = [[notification userInfo] objectForKey:NSUpdatedObjectsKey]; 
    for (NSManagedObject *object in objects) { 
     [[context objectWithID:[object objectID]] willAccessValueForKey:nil]; 
    } 

    [context performBlock:^{ 
     [context mergeChangesFromContextDidSaveNotification:notification]; 
     NSError *error = nil; 
     if (![context save:&error]) { 
      NSLog(@"error merging changes %@, %@", error, [error userInfo]); 
     } 
    }]; 
} 
0

您正在創建一個全新的提取結果控制器。所以沒有改變(像插入,刪除,更新),所以委託不被調用。有兩種方法可以解決這個問題。

首先,你可以使用現有的FRC,只是改變它的讀取請求的謂詞(讀取請求本身是readonly)。然後你只需撥打performFetch。根據您的需要,這可能就足夠了。

第二,如果你需要擦拭FRC並創建一個新的,你需要調用reloadData在表視圖。我通常通過一些實例變量改變FRC創建的邏輯做到這一點(以下蘋果模板,該FRC被延後創建),以及剛剛成立的FRC到nil並調用[self.tableView reloadData];

+0

他發佈的代碼是他如何創建提取的結果控制器。如果你閱讀他的問題,很明顯,他正在使用該獲取的結果控制器進行讀取操作,並期望看到委託回調(但不是,至少是一次移動)。獲取的結果控制器使用'performFetch:'來填充它的獲取對象,然後監聽影響與其獲取請求匹配的對象的上下文更改 - 這是觸發委託回調的原因。 – quellish 2014-09-01 04:21:18

+0

@quellish我明白你想說什麼。這就是爲什麼我在我的答案中提出了建議。 – Mundi 2014-09-01 06:14:37

+0

FRC的謂詞沒有改變。只有底層數據的排序字段的值正在改變。 – ninjudd 2014-09-08 15:57:16

相關問題