Ios 不同视图控制器中的NSFetchedResultsController是否相互更新?

Ios 不同视图控制器中的NSFetchedResultsController是否相互更新?,ios,objective-c,core-data,nsfetchedresultscontroller,Ios,Objective C,Core Data,Nsfetchedresultscontroller,好吧,我对这个问题越来越笼统了,因为我注意到我的应用程序中有几个滞后。我注意到了重新排序的问题,但它也发生在其他地方。我有一个CoreDataViewController类,它是我所有表视图控制器的子类。在这个类中,我基本上拥有了所有NSFetchedResultsController委托方法,就像它们在apple文档中一样 然后,我尝试了解此NSFetchedResultsController注意到更改的频率,以了解我的时滞在哪里: - (void)controllerDidChangeCon

好吧,我对这个问题越来越笼统了,因为我注意到我的应用程序中有几个滞后。我注意到了重新排序的问题,但它也发生在其他地方。我有一个CoreDataViewController类,它是我所有表视图控制器的子类。在这个类中,我基本上拥有了所有NSFetchedResultsController委托方法,就像它们在apple文档中一样

然后,我尝试了解此NSFetchedResultsController注意到更改的频率,以了解我的时滞在哪里:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    if(self.suspendAutomaticTrackingOfChangesInManagedObjectContext) return;
    NSLog(@"ControllerDidChangeContent");
    TICK;
    [self.tableView endUpdates];
    TOCK;
}
例如,在我的视图控制器A中,我有一个获取请求(从viewDidLoad调用):

如果我在此视图控制器中更改对象的属性,我的日志只打印一次注释“ControllerDidChangeContent”。而且速度和预期的一样快。我的意思是,实际上只是一个简单的属性更改,只是更改一些数字或字符串等。例如:

spendingCategory.name = @"Hello world";
但是,如果我已经访问了另一个视图控制器,该控制器在viewDidLoad中也设置了NSFetchedResultsController,那么我的日志会打印两次。下面是第二个NSFetchedResultsController:

- (void)setupFetchedResultsController
{
    self.managedObjectContext = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).managedObjectContext;

    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SpendingCategory"];

    NSSortDescriptor *mainCatPosition = [[NSSortDescriptor alloc]
                            initWithKey:@"belongsToMainCategory.position" ascending:YES];
    NSSortDescriptor *spendingCatPosition = [[NSSortDescriptor alloc]
                            initWithKey:@"position" ascending:YES];

    request.sortDescriptors = [NSArray arrayWithObjects:mainCatPosition,spendingCatPosition,nil];
    request.predicate = [NSPredicate predicateWithFormat:@"liveBudget = %@", [NSNumber numberWithBool:YES]];

    self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request
                                                                       managedObjectContext:self.managedObjectContext
                                                                         sectionNameKeyPath:@"belongsToMainCategory.position"
                                                                                  cacheName:@"LiveBudget"];

}
我前面提到的简单属性更改需要更长的时间。这是因为现在我的日志打印了两次(!)controllerdChangeContent。第一个滴答声仍然和以前一样快,但第二个滴答声超过了一秒钟。我猜这是因为我有两个NSFetchedResultsController在监视同一个实体

  • 问题: 我还是不太明白他们为什么互相影响?我的意思是,好吧,我更新了一个视图控制器中的一个属性,所以另一个当然应该注意到这个更改,但是为什么会触发两个didChangeContent呢

  • 问题: 我怎样才能避免呢?或者我该如何改进


  • 我认为最好在使用此解决方案之前检查1[秒]停止的原因。
    就我自己而言,在同一环境下使用多个FRC时,我没有经历过这种延迟,所以我猜问题出在别处

    关于你的问题:

  • FRC正在侦听“NSManagedObjectContextObjectsIDChangeNotification”,因此所有FRC在相同对象的相同上下文上侦听时,都会在这些对象发生更改时触发其委托的方法。因此,很清楚为什么您的日志会打印两次(两个不同的FRC更改了其内容)

  • 1[sec]是阻塞主线程的很长时间,应该解决(使用仪器检查可以做什么)。正如我所提到的,当在同一上下文中使用FRC时,没有办法避免这种情况,但您可以为每个VC创建一个子上下文,并使FRC仅侦听该子上下文,然后在保存上下文链时,其他FRC才可以看到更改。只要你的VC堆栈不是很深,这应该不是一个真正的问题。在任何情况下,您都希望您的其他VC在更新tableview时得到更新,以提供流畅的用户体验,因此如果更新时间过长,您应该了解原因


  • 每个VC收到一个回调?或者一个收到重复的回调?表视图单元格包含哪些内容?您在哪里设置代理?每个VC在视图中设置FRC后会收到两次回调。表视图单元格不仅包含其所有属性(3个NSNUMBER,2个字符串)。并在视图中设置了代理。谢谢您的评论。如果我创建了一个子上下文并保存了它,那么我的另一个上下文会看到这些更改,即使不会再次执行提取?所以我可以让VC 1中的子上下文更改所有内容,保存上下文,然后VC 2立即显示更改?在再次检查之后,这个问题实际上主要出现在重新排序中,我自己更改属性并停止FRC检查更改,直到我完成。在改变了一切之后,我保存了上下文,让他再听一遍。([fetchedResult setValue:[NSNumber numberWithInt:i++]forKey:@“position”];)@MichiZH保存子上下文会将更改传播到父上下文,这反过来会转换为父上下文中的更改,而侦听父上下文的FRC将不需要重新提取对象(执行提取)。如果您的设置为VC1(父)->VC2(子)并且您在子上下文中进行了更改,则在保存子上下文时,父上下文将获得更改并更新VC1。在FRC委托方法中更改对象是有问题的,因为更改将在下一次运行循环中再次调用这些方法。不,我正在更改表委托方法中的顺序,只是停止获取结果控制器的侦听。是的,当然有多个对象发生了变化,但是控制器发生了变化,会发送两次,用于bot-FRC侦听。这需要时间。我正在考虑实现父子关系。我在另一种情况下解决了这个问题:由于具有相同提取的两个视图控制器中的一个仅用于显示,而另一个主要用于编辑,因此我刚刚删除了显示视图控制器中的所有委托方法,并始终在视图中显示一个新的提取。到目前为止,这个解决方案没有性能问题。或者这是一个糟糕的解决方案?您的重新排序方法效率很低,会一个接一个地损坏对象(第一次运行时速度很慢)。其次,您忽略了Marcus S.Zarra关于更新FRC委托方法中对象的建议。您的设置似乎很复杂。在每个
    视图上执行提取和重建表视图将出现
    ,这也可能是复杂和低效的。
    
    - (void)setupFetchedResultsController
    {
        self.managedObjectContext = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).managedObjectContext;
    
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SpendingCategory"];
    
        NSSortDescriptor *mainCatPosition = [[NSSortDescriptor alloc]
                                initWithKey:@"belongsToMainCategory.position" ascending:YES];
        NSSortDescriptor *spendingCatPosition = [[NSSortDescriptor alloc]
                                initWithKey:@"position" ascending:YES];
    
        request.sortDescriptors = [NSArray arrayWithObjects:mainCatPosition,spendingCatPosition,nil];
        request.predicate = [NSPredicate predicateWithFormat:@"liveBudget = %@", [NSNumber numberWithBool:YES]];
    
        self.fetchedResultsController = [[NSFetchedResultsController alloc]initWithFetchRequest:request
                                                                           managedObjectContext:self.managedObjectContext
                                                                             sectionNameKeyPath:@"belongsToMainCategory.position"
                                                                                      cacheName:@"LiveBudget"];
    
    }