核心数据。对大型NSManagedObject的NSMutableSet进行排序

时间:2012-06-06 11:20:37

标签: iphone sorting core-data nsmanagedobject nsfetchrequest

我想获取大约200个NSManagedObject,每个大小约为5Mb。如果我使用executeFetchRequest,我会收到内存警告和应用程序崩溃(因为获取的NSManagedObjects出现在iPhone的RAM中)。如果我可以使用executeFetchRequest,我可以使用sortdescriptor按id排序数据。但我不能(或者可能是我应该为NSFetchRequest设置适当的属性,但我不知道,有什么属性)。 这就是我使用另一种方法加载大量数据的原因: 我有Entity Album,它有许多实体SpecificImage。我使用此代码来获取当前相册的所有图像:

- (NSMutableSet *)getAllSpecificImages
{
        NSString *entityName = kEntityName;
        AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        NSManagedObjectContext *context = appDelegate.managedObjectContext;
        NSEntityDescription *entityDesctiption = [NSEntityDescription 
                                                  entityForName: entityName
                                                  inManagedObjectContext:context];
        // check if town exists
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id == %d", self.CurrentCategoryItemID];
        NSFetchRequest *requestToCheckExistense = [[NSFetchRequest alloc] init];
        [requestToCheckExistense setEntity:entityDesctiption];
        [requestToCheckExistense setPredicate:predicate];
        NSArray *objects = [context executeFetchRequest:requestToCheckExistense error:nil];
        [requestToCheckExistense release];
        if (objects == nil)
        {
            NSLog(@"there was an error");
            return nil;
        }
        NSManagedObject *object;
        if ([objects count] > 0)
        {
            // edit item
            object = [objects objectAtIndex:0];

        }
        else
        {
            // if object doesn't exist, find max id to imlement autoincrement
            NSFetchRequest *request = [[NSFetchRequest alloc] init];
            [request setEntity:entityDesctiption];
            NSArray *allobjects = [context executeFetchRequest:request error:nil];
            [request release];
            NSInteger newID = 1;
            if ([allobjects count] > 0)
            {
                NSNumber *maxID = [allobjects valueForKeyPath:@"@max.id"];
                newID = [maxID intValue] + 1;
            }

            // write item
            object = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; 
            [object setValue:[NSNumber numberWithInt:newID] forKey:@"id"];
            self.CurrentCategoryItemID = newID;
        }

    NSMutableSet *set = [object mutableSetValueForKey:@"specificImages"];
    return set;
}

然后我得到NSManagedObjects数组

NSMutableArray *array = [NSMutableArray arrayWithArray:[setOfManagedObjectsSpecificImages allObjects]];

然后我尝试获取此NSManagedObjects的排序数组,我再次得到内存警告和应用程序崩溃。 我试着用

NSSortDescriptor *sortDiscriptor = [NSSortDescriptor sortDescriptorWithKey:@"id" ascending:YES];
[array sortUsingDescriptors:[NSArray arrayWithObject:sortDiscriptor]];

[self quickSort:array left:0 right:([array count] - 1)];

,其中

- (void)quickSort: (NSMutableArray *)arr left:(NSInteger)left right:(NSInteger) right
{
    @autoreleasepool {
        int i = left, j = right;

        int pivot = [((SpecificImage *)[arr objectAtIndex:(left + right) / 2]).id intValue];



        /* partition */

        while (i <= j) {
            while ([((SpecificImage *)[arr objectAtIndex:i]).id intValue] < pivot)
            {

                i++;
            }

            while ([((SpecificImage *)[arr objectAtIndex:j]).id intValue] > pivot)
            {

                j--;
            }

            if (i <= j) {

                [arr exchangeObjectAtIndex:i withObjectAtIndex:j];

                i++;

                j--;

            }

        };


        /* recursion */

        if (left < j)
        {
            [self quickSort:arr left:left right:j];
        }

        if (i < right)
        {
            [self quickSort:arr left:i right:right];
        }

    }

}

但这没有帮助。

从我的角度来看,当我得到一组NSManagedObjects时,它们不在RAM中。但在排序过程中,它们出现在RAM中。

我想要排序NSMutableSet(尝试设置:

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"specificImages.id" ascending:YES];

但我得到了

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here'

我描述的这个问题是另一个问题NSSortDescriptor to-many relationships

从我的观点来看,我看到了两种方法: 1)executeFetchRequest,但是提供:对象没有出现在RAM中(我不知道如何,但我几乎可以确定它是可能的) 2)更改我的快速排序以提供:对象不会出现在RAM中

更新 这是我的代码,我尝试使用executeFetchRequest获取对象(对象在RAM中,我希望它是故障对象(不在RAM中)):

+ (NSMutableSet *)GetImagesWithPredicate:(NSPredicate *)predicate
{
    NSString *entityName = kEntityName;
    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];;
    NSManagedObjectContext *context = appDelegate.managedObjectContext;
    NSEntityDescription *entityDesctiption = [NSEntityDescription 
                                              entityForName: entityName
                                              inManagedObjectContext:context];

    // find object
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDesctiption];
    [request setPredicate:predicate];
    NSArray *objects = [context executeFetchRequest:request error:nil];
    [request release];
    if (objects == nil)
    {
        NSLog(@"there was an error");
        return nil;
    }
    NSMutableSet *set = [NSMutableSet setWithArray:objects];
    return set;
}

其中谓词:

NSMutableArray *allID = [NSMutableArray array];
for (int i = 1; i < 639; i++)
{
      [allID addObject:[NSNumber numberWithInt:i]];
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id in %@", allID];

2 个答案:

答案 0 :(得分:3)

tl; dr the code。

CoreData有一个东西。它被称为错误。故障对象意味着您有对该对象的引用,该数据仍在存储中(您的“不在RAM中”版本)。要隐藏一个对象,你必须调用valueForKey:方法并获取任何属性(这会加载除关系之外的整个对象)。在进行排序时,核心数据会在内部调用valueForKey:,这会导致您的图像数据被加载。

我的建议:创建一个名为ImageDescriptor的单独实体,您可以在其中保存排序所需的所有属性。该实体将与实际的二进制图像数据保持一对一的关系,只有在需要时才会获取(即使用延迟提取)。

答案 1 :(得分:0)

我使用了Eimantas方法,但我得到了如何获取对象而不将其记录在RAM中。 我使用了includesPropertyValues