NSFetchedResultsController不显示来自不同上下文的更新 [英] NSFetchedResultsController doesn't show updates from a different context

查看:126
本文介绍了NSFetchedResultsController不显示来自不同上下文的更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 NSFetchedResultsController 和一些操作通过 NSOperationQueue 在不同的线程更新托管对象。



FRC(其谓词)如下所示:

   - (NSFetchedResultsController * )fetchedResultsController 
{
if(fetchedResultsController)return fetchedResultsController;

NSManagedObjectContext * mainContext = [self managedObjectContext];

NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@CheckinManagedObjectContext:mainContext]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@isSync ==%@,[NSNumber numberWithBool:NO]]];
[fetchRequest setFetchBatchSize:10];

fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil];
fetchedResultsController.delegate = self;

[fetchRequest release],fetchRequest = nil;

return fetchedResultsController;
}

主线程和线程操作有自己的管理对象上下文。



在线程化操作中,我将 isSync 属性从 NO YES 。要知道是什么是检查实体更新,主上下文传递到线程的 NSManagedObjectID
线程操作检索如下所示的托管对象:

   - (void)main 
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSManagedObjectContext * exportContext = [[NSManagedObjectContext alloc] init];
[exportContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];

// ...

检查* check =(检查*)[exportContext existingObjectWithID:objID error:& error];
check.isSync = [NSNumber numberWithBool:YES];

// ...

[exportContext save:& error];

[pool release],pool = nil;
}

当线程操作调用 save 调用 mergeChangesFromContextDidSaveNotification 通知,并且主上下文合并更改。

   - (void)contextChanged:(NSNotification *)notification 
{
if([notification object] == [self managedObjectContext])return;

if(![NSThread isMainThread]){
[self performSelectorOnMainThread:@selector(contextChanged :) withObject:notification waitUntilDone:YES];
return;
}

[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}

记录通知的说明
$ b

> NSFetchedResultsControllerDelegate 的委托方法未被调用。



这是很奇怪的,因为处理相同的上下文,主一个,允许监听变化和委托方法被调用,例如删除 UITableView 中的一个行对象。



我发现了一些有相同问题的主题。我已尝试所有的解决方法,但我找不到有价值的解决方案:


  1. NSFetchedResultsController不显示来自其他上下文的更新


  2. NSFetchedResultsController在从后台线程合并更新后不触发委托方法< a>


  3. NSFetchedResultsController with predicate忽略从不同NSManagedObjectContext合并的更改


/ p>

编辑



上面的代码在以前的模型中工作。



建议?



编辑2



这是我在 NSFetchedResultsController getter。这是我的错,但是当我写的帖子我没有复制它。

  NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@insertionDateascending:NO]; 
NSArray * sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor,nil];

//此处的代码
[fetchRequest setSortDescriptors:sortDescriptors];

现在,关于 Jody 最后评论


在你的NSOperation的main()中,你正在加载新对象,而在
中,它看起来像是为每个新对象设置isSync为YES。
用于fetchedResultsController的谓词对于具有isSync == NO的对象仅查找


我期望当属性 isSync 设置为YES时, NSFetchedResultsController 观察到更改并删除不匹配谓词。我错了?



请记住,当将更改从后台合并到主线程时,我可以看到几个对象更新了它们的 isSync 属性。

解决方案

你有基本的想法,代码...



请仔细检查您是否正确注册以接收来自后台MOC的通知。



注册以接收来自所有对象的所有通知。在该方法中,记录事件及其所有数据。当对象是MOC时,转储所有的属性(特别是已注册,插入,更新和删除的对象的列表)。



保存调用和合并通知的通知处理程序。



此外,您省略了很多代码,所以很难知道你实际上在做什么,但是你所包含的代码示例看起来像是将正在加载的所有对象的isSync设置为YES,但是你的获取请求只需要那些with isSync设置为NO。这些新对象都不会通过该谓词。



最后,仔细检查你的模型定义,确保你使用正确的数字类型。这可能是一个很大的问题来源。



EDIT



我忘记了...您的抓取请求没有排序描述符。创建FRC时,您的获取请求必须至少包含一个排序描述符...如果您有多个部分,则第一个排序描述符用于将对象分组。



要跟进Alexsander的评论...我在我的帖子开头提到它,但你肯定不想收听来自MOC的通知,除非它是众所周知的(除非,当然,你只是记录调试目的)。你应该知道你正在使用的MOC。



此外,我建议使用父/子MOCs这种类型的处理,但你正在做什么应该工作,如果做



父类(私有并发类型)
主类型(主并发类型)与你的背景MOCs,只是让他们设置主要的moc作为他们的父母。当他们保存时,他们的对象被直接注入主MOC。



或者,你可以将你的后台MOC作为父亲的母亲,然后再将主 MOC只能重新发出提取,以从父级获取数据。


I have an NSFetchedResultsController and a few operations updates managed objects on separate threads via NSOperationQueue.

The FRC (with its predicate) looks like this:

- (NSFetchedResultsController*)fetchedResultsController
{
    if(fetchedResultsController) return fetchedResultsController;

    NSManagedObjectContext* mainContext = [self managedObjectContext];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[NSEntityDescription entityForName:@"Check" inManagedObjectContext:mainContext]];
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"isSync == %@", [NSNumber numberWithBool:NO]]];
    [fetchRequest setFetchBatchSize:10];

    fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil];
    fetchedResultsController.delegate = self;

    [fetchRequest release], fetchRequest = nil;

    return fetchedResultsController;
}

The main thread and the threaded operation have their own managed object contexts. They only share the same coordinator.

Within the threaded operation I change the isSync property from NO to YES. To know what is Check entity to update, the main context passes to the threaded one a NSManagedObjectID. The threaded operation retrieves the managed object like the following:

-(void)main
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSManagedObjectContext *exportContext = [[NSManagedObjectContext alloc] init];
    [exportContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];

    //...

    Check* check = (Check*)[exportContext existingObjectWithID:objID error:&error];
    check.isSync = [NSNumber numberWithBool:YES];

    //...

    [exportContext save:&error];

    [pool release], pool = nil;
}

When the thread operation calls a save the mergeChangesFromContextDidSaveNotification notification is called and the main context merges the changes.

- (void)contextChanged:(NSNotification*)notification
{
    if ([notification object] == [self managedObjectContext]) return;

    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES];
        return;
    }

    [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}

Logging the description of the notification leads to verify that changes are performed correctly.

My problem

Delegates methods of NSFetchedResultsControllerDelegate are not called.

This is quite strange since dealing with the same context, the main one, allows to listen for changes and delegates methods are called, e.g. deleting a row object in the UITableView.

I've found some topics on SO with the same problem. I've tried all the workarounds but I cannot find a valuable solution:

  1. NSFetchedResultsController not showing updates from other contexts

  2. NSFetchedResultsController not firing delegate method after merging update from background thread

  3. NSFetchedResultsController with predicate ignores changes merged from different NSManagedObjectContext

Thank you in advance.

Edit

The code above was working in a previous model. Then I created a new model copying (and pasting) entities from the previous one and now it doesn't work anymore.

Suggestions?

Edit 2

This is the predicate I'm using in NSFetchedResultsController getter. It's my fault, but when I wrote the post I didn't copy it.

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"insertionDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

// previous code here
[fetchRequest setSortDescriptors:sortDescriptors];

Now, about Jody last comment

In the main() of your NSOperation, you are loading new objects, and in there it looks like you are setting isSync to YES for each new object. The predicate you use for the fetchedResultsController is looking only for objects that have isSync == NO.

I expecting that when the property isSync is set to YES, the NSFetchedResultsController observes that changes and removes rows that not match the predicate. Am I wrong?

Remember that when merging changes from the background to the main thread, I'm able to see that few objects have updated their isSync property.

解决方案

You have the basic idea, so there is probably a bug somewhere in your code...

Double check that you are properly registering to receive the notification from the background MOC.

Register to receive all notifications from all objects. In that method, log the event, and all its data. When the object is a MOC, dump all its properties (especially the lists of registered, inserted, updated, and deleted objects).

Put a log statement right before and after the save call, and in the notification handler for merging the notification.

Also, you omitted a lot of code so it's hard to know what you are actually doing, but the code sample you included looks like it is hard setting isSync to YES for all objects being loaded, but your fetch request only wants those with isSync set to NO. None of those new objects will pass that predicate.

Finally, double check your model definition and make sure you are using the right number type. This can be a big source of problems.

EDIT

Oh yeah, I forgot... your fetch request does not have a sort descriptor. When you create a FRC, your fetch request must contain at least one sort descriptor... if you have multiple sections, the first sort descriptor is used to group the objects into sections.

To follow up on Alexsander's comment... I alluded to it at the beginning of my post, but you certainly do not want to listen to notifications from a MOC unless it is well known as one of yours (unless, of course, you are just logging for debugging purposes). You should know about the MOC you are using.

Furthermore, I would suggest using parent/child MOCs for this type of processing, but what you are doing should work if done properly.

Parent (private concurrency type) Main (main concurrency type)

Then, with your background MOCs, just have them set the main moc as their parent. When they save, their objects get injected directly into the main MOC. The main MOC can then issues saves at later times to put them onto disk.

Or, you can parent you background MOC to the "parent" and then the "main" MOC can just reissue the fetch to get the data from the parent.

这篇关于NSFetchedResultsController不显示来自不同上下文的更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆