【问题标题】:refreshing an nsfetchedresultscontroller not tied to a uitableview刷新未绑定到 uitableview 的 nsfetchedresultscontroller
【发布时间】:2013-12-16 06:07:23
【问题描述】:

我正在编写一个使用多个 NSFetchedResultsControllers (FRC) 的应用程序,每个应用程序用于我的数据模型中的不同托管对象子类。其中几个 FRC 是 UITableViewControllers 的一部分,但有几个不是。我有两个问题:第一,当我向 MOC 添加新对象时,为什么我的一个 FRC 没有更新,第二,我是否应该为此目的使用 FRC?我认为这可以让我不必在所有代码中都放入 fetch 请求,但也许只有将 FRC 与 tableview 或其他此类对象一起使用才有意义。

所以,这里是详细信息。

不与tableview 绑定的 FRC 之一是跟踪时间表的 FRC。 SetScheduleViewController 具有以下属性(以及其他属性),这些属性是通过父视图控制器传入的:

  @property (weak, nonatomic) NSFetchedResultsController *scheduleFetchedResultsController;
  @property (weak, nonatomic) NSManagedObjectContext *managedObjectContext;

这个 FRC 是由另一个对象(它维护一个指向它的强指针)通过以下代码创建的

- (NSFetchedResultsController *)scheduleFetchedResultsController  {


    if (_scheduleFetchedResultsController != nil) {
        return _scheduleFetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Schedule" inManagedObjectContext:self.managedObjectContext];

    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"start" ascending:NO];
    NSArray *sortDescriptors = @[sortDescriptor];

    [fetchRequest setSortDescriptors:sortDescriptors];

    NSFetchedResultsController *fRC = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];


    NSError *error = nil;
    if (![fRC performFetch:&error]) {
        IFLErrorHandler *errorHandler;
        [errorHandler reportErrorToUser:error];
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    self.scheduleFetchedResultsController = fRC;

    return self.scheduleFetchedResultsController;
}

(顺便说一句:cacheName 设置为 nil 的原因是我似乎只能将缓存名称分配给此应用程序中的众多 FRC 中的一个,或者应用程序崩溃......如果只有一个 FRC 是给定一个缓存名称,其余的缓存名称设置为 nil,一切似乎都很好,尽管我担心没有缓存,随着持久存储大小的增长,性能可能会很糟糕......但这是另一回事)

SetScheduleViewController 中,可以创建或删除计划,并在加载SetScheduleViewController 时加载最近创建的计划。创建计划时,会创建一个新的计划管理对象,然后将 MOC 保存如下:

 Schedule *newSchedule= [NSEntityDescription insertNewObjectForEntityForName:@"Schedule" inManagedObjectContext:self.managedObjectContext];
 newSchedule.start=newStartTime; 
 //etc

  NSError *saveError;
    if (![self.managedObjectContext save:&saveError]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", saveError, [saveError userInfo]);
        abort();

这成功保存了新的 MO,但 FRC 没有更新...我已经检查了几种方法...例如,如果在保存新计划后我重新输入 SetScheduleViewController 并检查 @987654331 @count] 它没有增加。但是,如果我退出应用程序并再次打开它,你瞧,FRC 获取的对象计数会增加,并且新对象确实存在。

我应该注意到scheduleFetchedResultsController 没有分配代表,这与附加到tableviewcontrollers 的FRC 不同,它们都工作正常。我没有分配委托,因为据我所知,tableviewcontrollers 中的 FRC 委托方法仅在 FRC 更改内容时处理更新 tableview...我看不到任何刷新 FRC 本身的委托方法添加了一个新对象并保存了 MOC。

所以,我的两个问题又是:1) 为什么 FRC 不刷新(以及我如何让它刷新),2) 使用 FRC 来管理未绑定的托管对象的获取结果是否有意义到tableview,我是否应该在每次需要访问对象列表时简单地从 MOC 执行新的提取?

非常感谢任何帮助。

【问题讨论】:

    标签: ios nsfetchedresultscontroller


    【解决方案1】:

    NSFetchedResultsController 文档中指出,如果没有设置委托,FRC 处于“无跟踪”模式。此外,委托必须至少实现一种变更跟踪委托方法才能启用变更跟踪。

    委托不必是表格视图控制器,因此您可以使用您的 SetScheduleViewController 作为委托,只需实现 controllerDidChangeContent: 委托方法。在该方法中,更新的 fetchedObjects 可用,您可以例如更新视图中的任何 UI 元素 控制器。

    更新:从 parentVC 传递 FRC 没有多大意义。 每个视图控制器都应该有自己的 FRC。所以scheduleFetchedResultsController应该是childVC中的一个方法。由于 FRC 是在 getter 方法中“延迟”创建的,因此必须在某个地方调用 getter。

    在表视图控制器的情况下,发生这种情况是因为所有表视图数据源方法 访问self.fetchedResultsController

    如果您的 childVC 无法访问 self.fetchedResultsController,则 FRC 不会被创建。这可能是为什么在 viewDidLoad 中调用 [self.fetchedResultsController performFetch:&error] 的原因(如另一个答案中所建议的那样)解决了您的问题。

    委托方法controllerDidChangeContent:如果结果会被调用 在 childVC 的生命周期内设置更改。这就是使用 FRC 的意义所在。

    如果您只想在加载 childVC 时获取当前对象集,那么 你不需要 FRC,你可以执行一个简单的 fetch,例如在viewDidLoad

    【讨论】:

    • 感谢您指出问题,但我仍然无法正常工作。当我创建 scheduleFetchedResultsController 时,我将委托设置为创建它的对象(在将该对象声明为 NSFetchedResultsControllerDelegate 之后)。 Apple 文档指出“重要提示:委托必须实现至少一种变更跟踪委托方法才能启用变更跟踪。提供 controllerDidChangeContent: 的空实现就足够了。”所以我确实这样做了,但它仍然不起作用
    • @daveadelson:在任何情况下(即使在无跟踪模式下)调用 performFetch 都会更新 fetchedObjects。跟踪模式应该也可以工作。您可以在 getter 方法中设置断点以找出它何时被调用。它是一种“懒惰的getter”方法,常见的模式是设置self.fetchedResultsController = nil 来强制重新创建。为什么 FRC 和上下文属性很弱? - 不过不管怎样,你的问题现在好像解决了,没关系。
    • 不将 FRC 设置为 nil 会破坏拥有 FRC 的目的吗? ...至于正在解决的问题,如果我不理解它,我在继续使用它时会感到不舒服...我想弄清楚。至于 FRC 属性很弱,我假设因为父级有一个指向它们的强指针,所以我应该有来自它们传递到的任何子级 VC 的弱指针。这是不正确的吗?
    • ps。我确实在 getter 中放了一个断点,它根本没有被调用,除了 FRC 是由 parentVC 首次创建时
    • @daveadelson:我最后的评论有点误导。我已经用更多可能有用的信息更新了答案。
    【解决方案2】:

    我以前也遇到过同样的问题。原因是您没有执行 FRC 的提取。 在 -viewDidLoad 上添加以下代码:

    NSError *error;
        if (![self.fetchedResultsController performFetch:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }
    

    【讨论】:

    • 再看,他确实有 performFetch: 调用。
    • 实际上,我尝试了 Aditya 的建议并解决了它...我不知道如何撤消某人的反对票(我没有足够的声望点来投票给自己),但这确实解决问题。回复:Kendall 说什么,我在 getter 中执行 fetch 请求,但如果 FRC 已经存在,则不会在那里调用它(至少,我认为这是问题所在......要么那个,要么 getter 没有被调用,虽然不应该这样)...底线:将 performFetch 放在 SetScheduleViewController 的 viewDidLoad 中有效...想了解原因。
    • ps。应该注意的是,按照 Martin 的建议,在将 FRC 置于跟踪模式之后,我尝试了 Aditya 的建议,方法是分配一个委托并在该委托中添加一个空的 controllerDidChangeContent 方法……但我只是注释掉了委托分配和事情 仍然 感谢 Aditya 的代码......这对我来说非常 令人费解,因为没有委托分配,FRC 不应该处于每个 Apple 的跟踪模式,正如 Martin 指出的那样
    猜你喜欢
    • 2014-06-11
    • 1970-01-01
    • 2013-05-17
    • 1970-01-01
    • 2023-03-15
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 2011-03-24
    相关资源
    最近更新 更多