NSSortdescriptor对从NSManagedContext提取结果无效 [英] NSSortdescriptor ineffective on fetch result from NSManagedContext

查看:96
本文介绍了NSSortdescriptor对从NSManagedContext提取结果无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用NSSortdescriptor(使用指向NSDate值的键)对NSFetchRequest结果进行排序.没有明显的原因,我的提取结果完全是随机的.

我正在使用的NSManagedObjectContext通过在NSOperation的子类上创建的嵌套子上下文的保存进行了更新.我知道所有这一切都已成功完成,因为我可以从父(主)上下文中获取所有需要的数据.从中获取只是不会按日期排序!

奇怪的是;在两个日期之间选择实体(称为"Tweet")的谓词就可以了!

下面是一些代码来说明我的问题:

NSSortDescriptor* timeDescriptor = [NSSortDescriptor
                                        sortDescriptorWithKey:@"time"
                                        ascending:NO
                                        selector:@selector(compare:)];

NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Tweet"];
[request setSortDescriptors:[NSArray arrayWithObjects:timeDescriptor, nil]];

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"((time >= %@) AND (time <= %@))",startDate,endDate];
[request setPredicate:predicate];

NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:[[NSApp delegate] managedObjectContext]];
[context performBlock:^{
    NSError* error = nil;
    NSArray* results = nil;

    results = [context executeFetchRequest:request error:&error];
    // Results here are not ordered correctly

    // 2nd try sorting results using fetched array (works!)
    results = [results sortedArrayUsingDescriptors:[NSArray arrayWithObjects:timeDescriptor, nil]];

    // This works too but not needed anymore
    /*results = [results sortedArrayUsingComparator:^(id obj1, id obj2) {
        Tweet* tweet1 = (Tweet*)obj1;
        Tweet* tweet2 = (Tweet*)obj2;
        //return [tweet1.time compare:tweet2.time]; // ascending
        return [tweet2.time compare:tweet1.time]; // descending
    }];*/

    if ([results count] > 0) {
        for (uint i = 0; i < [results count]; i++) {
            Tweet* tweet = [results objectAtIndex:i];
            NSDate* date = Tweet.time;
            NSLog(@"tweet date: %@", date);
        }
    }
}];

有人可以告诉我为什么NSSortDescriptor对我的提取不起作用吗?

谢谢!

-更新-

当我从主线程上的主(父)managedObjectContext中获取而不使用performBlock方法时,似乎NSSortDescriptor可以正常工作.这仍然不能帮助我在NSPrivateQueueConcurrencyTypemanagedObjectContext上进行排序提取.在performBlock内部创建NSFetchRequest,NSSortDescriptor和NSPredicate也不能解决问题.

解决方案

我也遇到了这个问题. 我发现,除非将数据一直保存到Persistent Store,否则如果主上下文中的数据很脏(即已修改),则排序将无法进行.

例如,如果上下文是干净的,没有挂起的更改,则排序有效. 如果仅在父上下文中更改实体的一个属性,则私有队列子上下文中的排序将不起作用.真不幸我现在也使用数组方法进行排序,但是它的速度不如NSFetchRequest中的排序,特别是因为我的数据已经被该键索引了.在获取请求中对它进行排序会更快得多.

我的猜测是,由于上下文中有未保存的更改,并且NSFetchRequest转到SQLite数据库本身(该更改尚不存在(上下文未保存)),因此它根本无法在数据库级别进行排序. /p>

但是总的来说,这非常令人困惑并且闻起来像个错误.

I'm trying to sort my NSFetchRequest result using a NSSortdescriptor using a key pointing to a NSDate value. My fetch results come out totally random for no clear reason.

The NSManagedObjectContext I'm using is updated with a save from a nested child context created on a subclass of NSOperation. I know all this is done successfully because I can get all the data needed from the parent (main) context. Fetching from it just wont sort on date!

Strange thing is; predicates for selecting the entities (called "Tweet") between two dates works just fine!

Here's some code to illustrate my problem:

NSSortDescriptor* timeDescriptor = [NSSortDescriptor
                                        sortDescriptorWithKey:@"time"
                                        ascending:NO
                                        selector:@selector(compare:)];

NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"Tweet"];
[request setSortDescriptors:[NSArray arrayWithObjects:timeDescriptor, nil]];

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"((time >= %@) AND (time <= %@))",startDate,endDate];
[request setPredicate:predicate];

NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[context setParentContext:[[NSApp delegate] managedObjectContext]];
[context performBlock:^{
    NSError* error = nil;
    NSArray* results = nil;

    results = [context executeFetchRequest:request error:&error];
    // Results here are not ordered correctly

    // 2nd try sorting results using fetched array (works!)
    results = [results sortedArrayUsingDescriptors:[NSArray arrayWithObjects:timeDescriptor, nil]];

    // This works too but not needed anymore
    /*results = [results sortedArrayUsingComparator:^(id obj1, id obj2) {
        Tweet* tweet1 = (Tweet*)obj1;
        Tweet* tweet2 = (Tweet*)obj2;
        //return [tweet1.time compare:tweet2.time]; // ascending
        return [tweet2.time compare:tweet1.time]; // descending
    }];*/

    if ([results count] > 0) {
        for (uint i = 0; i < [results count]; i++) {
            Tweet* tweet = [results objectAtIndex:i];
            NSDate* date = Tweet.time;
            NSLog(@"tweet date: %@", date);
        }
    }
}];

Can anybody tell me why the NSSortDescriptor isn't working for my fetches?

Thanks!

-- Update --

It seems the NSSortDescriptor works fine when I fetch from the main (parent) managedObjectContext on the main thread without using the performBlock method. This still doesn't help me do sorted fetches on a NSPrivateQueueConcurrencyType managedObjectContext. Creating the NSFetchRequest, NSSortDescriptor and NSPredicate inside the performBlock doesn't fix the problem either.

解决方案

I hit the problem as well. I've found out that unless the data is saved all the way back to Persistent Store, the sorting won't work if the data in the master context is dirty, i.e. modified.

For example, if the contexts are clean, without pending changes, the sorting works. If I only change one attribute of an entity in the parent context, then the sorting in the private queue child context doesn't work. That's very unfortunate. I also do sorting with array method now but it's not that fast as sorting in the NSFetchRequest, especially since my data is already indexed by that key. It would've been much faster to sort it in the fetch request.

My guess is that since there are unsaved changes in the context and NSFetchRequest goes to the SQLite database itself, where the changes do not yet exist (context not saved), it can't sort on the database level at all.

But overall, it's very confusing and smells like a bug.

这篇关于NSSortdescriptor对从NSManagedContext提取结果无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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