閱讀幾十個類似的問題,我想先從這個說法:「我沒設置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不會更新它的行。
您發佈了錯誤的代碼。有趣的是如何將數據導入數據庫,以及如何爲導入和讀取結果控制器設置核心數據堆棧。 –
我在UPD1中添加了一些你所要求的細節。我希望現在更清楚我是如何以此結束的...... – Arseniy
關於更新的任何想法? – Arseniy