Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Paging results from Core Data requests

I have a relatively simple core data sqlite database. I am trying to get results from DB one page at a time.


    NSFetchRequest* request = [[[NSFetchRequest alloc] init] autorelease];
    [request setEntity:[...]];

    [request setPredicate:[NSPredicate predicateWithFormat:@"flaggedTime != nil"]];

    NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"flaggedTime" ascending:NO];
    [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];

    [request setFetchLimit:pageSize];
    [request setFetchOffset:((pageIndex - 1) * pageSize)];    

    NSArray* results = [self.context executeFetchRequest:request error:NULL];

pageSize is 30, pageIndex on testing data is 1, 2, 3 or 4 (there are about 80 items in DB, so pageIndex = 4 should return no items). Predicate and sorting works fine, results are successfully returned. Fetch limit works fine, too. No errors are returned.

Problem: I always get results from the first page, as if fetchOffset was not set. I tried to remove the predicate and the sorting but to no avail. The only situation when I could make fetchOffset work was when I used values under 30. Of course, that is meaningless for paging...

Does anybody know why? I will be really thankful for every answer.

Update: I am speaking about iOS. Tested on 4.2 and 5.0.

Update 2: To simplify the problem.


    NSFetchRequest* request = [[[NSFetchRequest alloc] init] autorelease];
    [request setEntity:[...];

    NSError* error = nil;

    NSManagedObjectContext* context = [...];

    NSUInteger count = [context countForFetchRequest:request error:&error];
    assert(error == nil);

    NSLog(@"Total count: %u", count);

    request.fetchOffset = 0;    
    request.fetchLimit = 30;

    NSLog(@"Fetch offset: %u, limit: %u", request.fetchOffset, request.fetchLimit);

    NSArray* page1 = [context executeFetchRequest:request error:&error];
    assert(error == nil);

    NSLog(@"Page 1 count: %u", page1.count);

    request.fetchOffset = 30;    
    request.fetchLimit = 30;

    NSLog(@"Fetch offset: %u, limit: %u", request.fetchOffset, request.fetchLimit);

    NSArray* page2 = [context executeFetchRequest:request error:&error];
    assert(error == nil);

    NSLog(@"Page 2 count: %u", page2.count);

gives:

Total count: 34
Fetch offset: 0, limit: 30
Page 1 count: 30
Fetch offset: 30, limit: 30
Page 2 count: 30 (ERROR: should give 4)
like image 281
Sulthan Avatar asked Oct 31 '11 14:10

Sulthan


People also ask

Is Core Data slow?

Coredata is very slow; swift.

What is Nsmanagedobjectcontext in Swift?

An object space to manipulate and track changes to managed objects.

What is Core Data in IOS?

Core Data is a framework that you use to manage the model layer objects in your application. It provides generalized and automated solutions to common tasks associated with object life cycle and object graph management, including persistence.


1 Answers

I just created a demo project that tries to recreate your scenario at its simplest form. I created a blank project, added 34 objects, then queried it with the exact same code you listed above. Below is the example:

CDAppDelegate * delegate = (CDAppDelegate*)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext * context = [delegate managedObjectContext];
for(int i = 0; i < 34;i++){
    CDObject * object = [NSEntityDescription insertNewObjectForEntityForName:@"CDObject"
                                                      inManagedObjectContext:context];
    [object setValue:i];
}
[delegate saveContext];

NSFetchRequest* request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:@"CDObject"
                               inManagedObjectContext:context]];

 NSError* error = nil;

 NSUInteger count = [context countForFetchRequest:request error:&error];
 assert(error == nil);

 NSLog(@"Total count: %u", count);

 request.fetchOffset = 0;    
 request.fetchLimit = 30;

 NSLog(@"Fetch offset: %u, limit: %u", request.fetchOffset, request.fetchLimit);

 NSArray* page1 = [context executeFetchRequest:request error:&error];
 assert(error == nil);

 NSLog(@"Page 1 count: %u", page1.count);

 request.fetchOffset = 30;    
 request.fetchLimit = 30;

 NSLog(@"Fetch offset: %u, limit: %u", request.fetchOffset, request.fetchLimit);

 NSArray* page2 = [context executeFetchRequest:request error:&error];
 assert(error == nil);

 NSLog(@"Page 2 count: %u", page2.count);

[request release];

The log is as shown:

2011-11-04 14:53:04.530 CDCoreDataTest[77964:207] Total count: 34
2011-11-04 14:53:04.531 CDCoreDataTest[77964:207] Fetch offset: 0, limit: 30
2011-11-04 14:53:04.532 CDCoreDataTest[77964:207] Page 1 count: 30
2011-11-04 14:53:04.533 CDCoreDataTest[77964:207] Fetch offset: 30, limit: 30
2011-11-04 14:53:04.533 CDCoreDataTest[77964:207] Page 2 count: 4

Using your code, I was able to get it up and running no problem. This was done with iOS 5.0 running on the simulator. Your code looks right to me for you are trying to accomplish, so there must be something going on with the fetch request or the context itself...

like image 195
kcharwood Avatar answered Oct 06 '22 00:10

kcharwood