Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/108.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Core Data和NSFetchedResultsController中的iOS中点击我的屏幕之前,重新加载数据不起作用_Ios_Objective C_Uitableview_Core Data - Fatal编程技术网

在Core Data和NSFetchedResultsController中的iOS中点击我的屏幕之前,重新加载数据不起作用

在Core Data和NSFetchedResultsController中的iOS中点击我的屏幕之前,重新加载数据不起作用,ios,objective-c,uitableview,core-data,Ios,Objective C,Uitableview,Core Data,以下是我目前的情况: 当我打开应用程序时,我的第一个屏幕上的UITableView为空 我从远程服务器获取数据,解析其生成的JSON对象,并将其保存到核心数据存储中,然后向存储发出获取请求,并将结果显示到前面提到的UITableView 但是,即使在解析保存查询后发布通知并重新加载表之后,表也不会更新,直到我点击或滚动屏幕 我尝试了[[u myTableView reloadData]和[\u myTableView performselectornmainthread:@selector(re

以下是我目前的情况:

  • 当我打开应用程序时,我的第一个屏幕上的
    UITableView
    为空

  • 我从远程服务器获取数据,解析其生成的JSON对象,并将其保存到核心数据存储中,然后向存储发出获取请求,并将结果显示到前面提到的
    UITableView

  • 但是,即使在解析保存查询后发布通知并重新加载表之后,表也不会更新,直到我点击或滚动屏幕

  • 我尝试了
    [[u myTableView reloadData]
    [\u myTableView performselectornmainthread:@selector(reloadData)with object:nil waitUntilDone:NO]来自通知,但结果根本没有改变,我仍然需要点击或滚动屏幕才能看到表上重新加载的数据

    我使用核心数据和NSFetchedResultsController,并确认我的查询已成功获取。只是重新加载表的问题。还要注意,我从
    AppDelegate.m
    调用通知,但出于上述原因(远程服务器数据获取),我的实际表视图位于另一个类
    RootViewController.m

    另外,当我写出以下代码时:

    
    
    -(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
        [_myTableView reloadData];
        [_myTableView endUpdates];
    }
    
    
    -(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
        NSLog(@"updated begin");
        [_myTableView beginUpdates];
    }
    
    我仍然需要通过点击屏幕来查看结果。但是,当我添加以下代码时:

    
    
    -(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
        [_myTableView reloadData];
        [_myTableView endUpdates];
    }
    
    
    -(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
        NSLog(@"updated begin");
        [_myTableView beginUpdates];
    }
    
    我甚至在点击屏幕后也看不到重新加载的数据

    此外,使用printf debug,我确认即使多次调用上述两个方法(可能与实际获取的托管对象调用次数相同,对吧?),在获取新添加的数据集后,
    numberofrowsinssection:
    cellforrowatinexpath:
    根本不会被调用

    注意,
    cellforrowsatindepath:
    被调用,如果我等待10秒或20秒左右,数据就会显示出来,这意味着即使我没有点击或滚动屏幕,数据也会显示出来。奇怪

    那么这里发生了什么?我如何解决这个奇怪的问题

    我使用iOS 7和Xcode 5

    更新 我发现,当我编写
    controllerWillChangeContext:
    时,无法看到重新加载的数据的原因是我遇到了以下错误:
    CoreData:error:严重的应用程序错误。在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托捕获到异常。无效更新:节0中的行数无效。更新后现有节中包含的行数(1)必须等于更新前该节中包含的行数(0),加上或减去从该节插入或删除的行数(0插入,0删除),加上或减去移入或移出该节的行数(0移入,0移出). 使用userInfo(null)
    。当我只实现
    controllerDidChangeContext:
    时,我没有得到这个错误,这仍然很奇怪,但是如果我同时写这两个,我就得到了错误,即使在点击屏幕后,表也不会显示数据


    所以也许我不能先显示空白结果,然后用新数据更新表,而应该让用户等待显示正确的数据

    controllerdChangeContent:
    中调用
    reloadData
    是错误的方法。实现
    NSFetchedResultsControllerDelegate时,该委托负责所有表视图更新


    从远程服务器的导入应在后台队列中完成。在通过
    mergeChangesFromContextDidSaveNotification
    将背景上下文与主上下文合并之前,您应该

  • 禁用
    NSFetchedResultsControllerDelegate
  • 将更改与主上下文合并
  • 重新加载您的表
  • 重新启用NSFetchedResultsControllerDelegate
  • 样本:

    fetchedResultsController.delegate = nil;
    [mainContext mergeChangesFromContextDidSaveNotification:notification];
    [tableView reloadData];
    fetchedResultsController.delegate = yourController;
    

    提示:使用NSFetchedResultsControllerDelegate时,您必须至少实现:

    • controllerWillChangeContent:
    • controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:
    • controllerDidChangeContent:

    阅读示例实现的文档:

    以下是一些示例代码

    在后台加载数据

    首先正确实现3个主要的fetchedResultsControllerDelegate方法,以确保UITableView正确获取更新

    • controllerWillChangeContent:
    • 控制器:didChangeObject:atIndexPath:forChangeType:newIndexPath:
    • controllerDidChangeContent:
    不要从这些委托方法中调用[tableView reload],仅使用Apple示例代码在tableView中正确添加/删除/更新行

  • 创建背景线程在背景线程上创建managedObjectContext(bgContext)
  • 在bgContext上注册保存通知的观察者(调用方法storesDidSave)
  • 批量运行后台加载/删除作业保存
  • 处理保存通知
  • 后台作业完成后,删除bgContext保存通知的观察者
  • 只要您有权访问主managedObjectContext,就可以将此代码放在任何位置—可能在运行后台加载作业的对象中。确保使用正确的线程进行处理。ManagedObjectContext不是线程安全的

    // NB - this may be called from a background thread so make sure we always run on the main thread !!
    // This is when transaction logs are loaded
    - (void)storesDidSave:(NSNotification*)notification {
    
        // Ignore any notifications from the main thread because we only need to merge data
        // loaded from other threads.
        if ([NSThread isMainThread]) {
            FLOG(@" main thread saved context ignore");
            return;
        }
    
        // Must pass these to the  main thread to process
        [[NSOperationQueue mainQueue] addOperationWithBlock:^ {
            FLOG(@"storesDidSave ");
    
            // Now merge into the MAIN managedObjectContext and save it.
            // If you don't save then objects in the main context don't seem to update correctly,        
            // especially deletes seem to don't show
            if (self.managedObjectContext) {
                [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
                        NSError *error;
                FLOG(@" saving moc");
                if (![self.managedObjectContext save:&error]) {
                    FLOG(@" error saving context, %@, %@", error, error.userInfo);
                }
            }
        }];
    }
    
    // Sample background dispatcher
    - (void)loadDataInBackground {
    
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
            [self loadData];
        });
    
    }
    // Background load job calls save after batches of 100 records
    - (void)loadData {
        FLOG(@"loadData called");
        _loadJobCount++;
        [self postJobStartedNotification];
    
        FLOG(@" waiting 5 seconds...");
        sleep(5);
        [self showBackgroundTaskActive];
    
        NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
    
        // Register for saves in order to merge any data from background threads
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(storesDidSave:) name: NSManagedObjectContextDidSaveNotification object:bgContext];
    
    
        while (self.persistentStoreCoordinator == nil) {
            FLOG(@" persistentStoreCoordinator = nil, waiting 5 seconds to try again...");
            sleep(5);
        }
    
        bgContext.persistentStoreCoordinator = [self persistentStoreCoordinator];
    
        FLOG(@" starting load...");
    
        for (int i = 1; i<=100; i++) {
            // Add a few companies
            [self insertNewCompany:bgContext count:10];
            [bgContext processPendingChanges];
    
            // Save the context.
            NSError *error = nil;
            if (![bgContext save:&error]) {
                FLOG(@"  Unresolved error %@, %@", error, [error userInfo]);
            }
            FLOG(@"   waiting 2 seconds...");
            sleep(0.01);
        }
    
        // Register for saves in order to merge any data from background threads
        [[NSNotificationCenter defaultCenter] removeObserver:self name: NSManagedObjectContextDidSaveNotification object:bgContext];
    
        FLOG(@" loading ended...");
        [self showBackgroundTaskInactive];
    
        sleep(2);
        _loadJobCount--;
        [self postJobDoneNotification];
    }
    
    //NB-这可能是从后台线程调用的,因此请确保始终在主线程上运行!!
    //此时将加载事务日志
    -(无效)存储IDSave:(NSNotification*)通知{
    //忽略来自主线程的任何通知,因为我们只需要合并数据
    //从其他线程加载。
    如果([NSThread isMainThread]){
    FLOG(@“主线程已保存co