问题

小明班上最近月考了,老师大明想要给一部分优秀的同学进行奖励,而另外一部分要进行查漏补缺。大明决定将总分排名前10的,各科成绩排名前10的以及排名最后10名的按从高到低的顺序找出来。以前大明都是在家用笔一个个划出来。不过最近大明在长沙戴维营教育接受了残酷的iOS培训,决定装逼一把,给自己的“肾6+”开发了一款应用。只要各科老师将成绩提交给他,就可以直接看到这些学生的成绩了,并且各种曲线、柱状图、饼图。每个学生的情况就好比没穿衣服一样”透明“。现在的问题是,大明并不想自己去实现各种筛选和排序算法。

解决方法

很快大明就想到了戴维营教育的博客上Core Data除了简单的存取功能外,还具备各种取数据的方法。

一、数据获取

Core Data中获取数据必须通过NSFetchRequest进行。我们有两种方式获取NSFetchRequest对象。

通过实体名称创建NSFetchRequest对象。

这种方式其实就是我们在前面两篇文章中用来获取数据的技巧。

NSFetchRequest*fetchRequest=[NSFetchRequestfetchRequestWithEntityName:@"Person"];//或者NSFetchRequest*fetchRequest=[[NSFetchRequestalloc]init];NSEntityDescription*entity=[NSEntityDescriptionentityForName:@"Person"inManagedObjectContext:context];fetchRequest.entity=entity;

通过模型文件中创建的请求模版创建。

//使用managedModel获取fetchRequest模版NSFetchRequest*fetchRequest=[appDelegate.managedObjectModelfetchRequestTemplateForName:@"personFR"];

我们可以指定fetchRequest的结果类型来获取不同数据,如存储的对象、结果数目等。

//NSFetchRequest*fetchRequest=[appDelegate.managedObjectModelfetchRequestTemplateForName:@"personFR"];//如果需要改变结果的类型,不能使用从模版生成的request对象NSFetchRequest*fetchRequest=[NSFetchRequestfetchRequestWithEntityName:@"Person"];//获取结果总数fetchRequest.resultType=NSCountResultType;

不过我们也不只一种获取结果数目的方式。在Context里面提供了一系列的操作request的方法,其中就包括了获取结果数目的功能。

NSFetchRequest*fetchRequest=[NSFetchRequestfetchRequestWithEntityName:@"Person"];//获取结果数目NSUIntegercount=[contextcountForFetchRequest:fetchRequesterror:nil];二、筛选结果集

大明已经可以得到所有学生的成绩信息了,接下来要做的就是对它们进行排序和筛选。

给学生成绩进行排序

NSFetchRequest*fetchRequest=[NSFetchRequestfetchRequestWithEntityName:@"Person"];//排序描述符,按score降序排列NSSortDescriptor*sort01=[NSSortDescriptorsortDescriptorWithKey:@"score"ascending:NO];//可以同时按多个属性进行排序fetchRequest.sortDescriptors=@[sort01];NSArray*result=[contextexecuteFetchRequest:fetchRequesterror:nil];if(result){_people=[NSMutableArrayarrayWithArray:result];for(NSObject*objin_people){NSLog(@"%@",[objvalueForKey:@"score"]);}}

结果:

2015-02-0410:54:16.59902-02-CoreData01[5832:276345]992015-02-0410:54:16.60002-02-CoreData01[5832:276345]602015-02-0410:54:16.60002-02-CoreData01[5832:276345]562015-02-0410:54:16.60002-02-CoreData01[5832:276345]45

筛选出成绩排名前十的学生

NSFetchRequest*fetchRequest=[NSFetchRequestfetchRequestWithEntityName:@"Person"];NSSortDescriptor*sort01=[NSSortDescriptorsortDescriptorWithKey:@"score"ascending:NO];fetchRequest.sortDescriptors=@[sort01];//限制只取前十,其实这是有问题的,万一有重复的分数,后面的就取不到了。fetchRequest.fetchLimit=10;NSArray*result=[contextexecuteFetchRequest:fetchRequesterror:nil];

使用NSPredicate筛选成绩高于90分的学生

NSPredicate*predicate=[NSPredicatepredicateWithFormat:@"score>=90"];fetchRequest.predicate=predicate;进阶

上面的这些数据获取方式都是同步的方式,如果数据量比较大的话,会显著的影响到程序的性能和用户体验。Core Data中也提供了异步数据获取功能。

AppDelegate*appDelegate=(AppDelegate*)[UIApplicationsharedApplication].delegate;NSManagedObjectContext*context=appDelegate.managedObjectContext;NSFetchRequest*fetchRequest=[NSFetchRequestfetchRequestWithEntityName:@"Person"];NSSortDescriptor*sort01=[NSSortDescriptorsortDescriptorWithKey:@"score"ascending:NO];fetchRequest.sortDescriptors=@[sort01];fetchRequest.fetchLimit=2;//异步请求NSAsynchronousFetchRequest*asyncRequst=[[NSAsynchronousFetchRequestalloc]initWithFetchRequest:fetchRequestcompletionBlock:^(NSAsynchronousFetchResult*result){for(NSObject*objinresult.finalResult){NSLog(@"%@",[objvalueForKey:@"score"]);}}];//执行异步请求[contextexecuteRequest:asyncRequsterror:nil];

注意:在使用异步请求的时候,需要设置NSManagedContext对象的并发类型,否则会出错。

2015-02-0412:12:50.70902-02-CoreData01[6083:300576]***Terminatingappduetouncaughtexception'NSInvalidArgumentException',reason:'NSConfinementConcurrencyTypecontext<NSManagedObjectContext:0x7fb27b72c5f0>cannotsupportasynchronousfetchrequest<NSAsynchronousFetchRequest:0x7fb27b71d750>withfetchrequest<NSFetchRequest:0x7fb27b7247a0>(entity:Person;predicate:((null));sortDescriptors:(("(score,descending,compare:)"));limit:2;type:NSManagedObjectResultType;).'

解决办法是在创建Context对象的时候,设置它的并发类型。

NSPersistentStoreCoordinator*coordinator=[selfpersistentStoreCoordinator];if(!coordinator){returnnil;}//创建Context对象,并设置并发类型_managedObjectContext=[[NSManagedObjectContextalloc]initWithConcurrencyType:NSMainQueueConcurrencyType];[_managedObjectContextsetPersistentStoreCoordinator:coordinator];参考资料

Core Data异步操作:http://code.tutsplus.com/tutorials/ios-8-core-data-and-asynchronous-fetching--cms-22241

Core Data并发操作:http://code.tutsplus.com/tutorials/core-data-from-scratch-concurrency--cms-22131

批量更新Core Data:http://code.tutsplus.com/tutorials/ios-8-core-data-and-batch-updates--cms-22164

本文档由长沙戴维营教育整理。