核心数据请求的分页结果

我有一个相对简单的核心数据sqlite数据库。 我试图一次从DB页面获取结果。

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是30,testing数据的pageIndex是1,2,3或4(DB中约有80个项目,所以pageIndex = 4应该不返回任何项目)。 谓词和sorting工作正常,结果成功返回。 取限制也可以正常工作。 没有错误返回。

问题:我总是从第一页得到结果,就像没有设置fetchOffset一样。 我试图删除谓词和sorting,但无济于事。 唯一的情况,当我可以使fetchOffset的工作是当我使用30以下的值。当然,这是毫无意义的分页…

有人知道为什么吗? 我会很感激每一个答案。

更新:我正在谈论iOS。 testing4.2和5.0。

更新2:简化问题。

 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); 

得到:

总数:34
取偏移量:0,限制:30
第1页数:30
取偏移量:30,限制:30
计数:30(错误:应该给4)

当您对未保存的上下文运行提取请求时,忽略NSFetchRequestpageOffset属性(有时?)。 请注意,OP上下文中的代码永远不会被保存,而在附加到@kcharwood答案的代码片段中,它实际上是保存的。 这里是一个例子:

 - (void) printArrayOfTestEntities:(NSArray *)array{ NSMutableString * s = [NSMutableString new]; NSArray * numbers = [array valueForKey:@"someField"]; for (NSNumber * number in numbers){ [s appendString:[NSString stringWithFormat:@"%d ", [number intValue]]]; } NSLog(@"fetched objects: %@ \rcount: %d", s, array.count); } /* example itself */ NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; [context setPersistentStoreCoordinator:persistentStoreCoordinator]; for(int i = 0; i < 34;i++){ NSManagedObject * object = [NSEntityDescription insertNewObjectForEntityForName:@"TestEntity" inManagedObjectContext:context]; [object setValue:@(i) forKey:@"someField"]; } NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"TestEntity"]; request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"someField" ascending:YES]]; request.fetchLimit = 30; NSArray * result = [context executeFetchRequest:request error:nil]; [self printArrayOfTestEntities:result]; request.fetchOffset = 30; result = [context executeFetchRequest:request error:nil]; [self printArrayOfTestEntities:result]; [context save:&error]; request.fetchOffset = 0; result = [context executeFetchRequest:request error:nil]; [self printArrayOfTestEntities:result]; request.fetchOffset = 30; result = [context executeFetchRequest:request error:nil]; [self printArrayOfTestEntities:result]; 

日志:

 2014-03-01 11:30:06.986 coredatatest[19771:70b] fetched objects: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 count: 30 2014-03-01 11:30:06.990 coredatatest[19771:70b] fetched objects: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 count: 30 2014-03-01 11:30:06.995 coredatatest[19771:70b] fetched objects: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 count: 30 2014-03-01 11:30:06.997 coredatatest[19771:70b] fetched objects: 30 31 32 33 count: 4 

我刚刚创build了一个演示项目,试图以最简单的forms重新创build您的场景。 我创build了一个空白项目,添加了34个对象,然后用上面列出的完全相同的代码查询它。 下面是例子:

 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]; 

日志如下所示:

 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 

使用你的代码,我能够得到它并运行没有问题。 这是在模拟器上运行的iOS 5.0完成的。 你的代码看起来是正确的,因为你正在努力完成,所以一定有一些事情正在取得请求或上下文本身…

核心数据内置了分页function,这非常简单,只需在获取请求上设置fetchBatchSize即可。 当设置抓取只是查询所有的对象为故障,基本上只是一个指针和它的行索引是最小的内存,成为一种特殊的数组称为批错误数组。 我可以想象在大多数情况下这是很好的,虽然我还没有看到它将使用多less内存它将用于大量的行。 然后,当您访问故障logging的属性时循环访问该数组,它将查询该logging的数据库,然后查找下一个logging,直到您为该批处理大小设置的数字。 这允许你像往常一样循环你的结果,但在后台它加载在批量的数据。 从iOS 9.2开始,最小批量大小是4,所以没有一个数字小于这个数字。