Core Data 简单查询、
来源:互联网 发布:fedora centos 很像吗 编辑:程序博客网 时间:2024/05/22 23:53
简单的查询通过创建 NSFetchRequest
来从 CoreData 中取得数据。
下面展示四种查询数据的方式:
//1 let fetchRequest1 = NSFetchRequest() let entity = NSEntityDescription.entityForName("Person", inManagedObjectContext: managedObjectContext)! fetchRequest1.entity = entity第一种方法通过默认初始化`NSFetchRequest`,从 managedContext 来创建 Person 类的 EntityDescription,然后设置fetchRequest的entity来完成。 //2 let fetchRequest2 = NSFetchRequest(entityName: "Person")
第二种方法可以在初始化NSFetchRequest的时候传入EntityName来完成,这是一种便捷的快速方法,在init的时候就制定了Entity。
“`swift
//3
let fetchRequest3 = managedObjectModel.fetchRequestTemplateForName(“peopleFR”)
第三种通过调用`managedObjectModel`的`.fetchRequestTemplateForName`方法来获取 NSFetchRequest。在Xcode的 Data Model Editor 界面中可以手动设置一些针对用户需求常用的fetch属性,可以使用这种方法来快速调用。 ```swift //4 let fetchRequest4 = managedObjectModel.fetchRequestFromTemplateWithName("peopleFR", substitutionVariables: ["NAME" :"Ray"])
第四种基于第三种,但是会在第三种的基础上使用substitutionVariables
进行再次的筛选。
在Editor上创建 Fetch Template
在 Data Model Editor 界面上长时间按住 Add Entity 的那个按钮,选择Add Fetch Request
。
之后如果是查询一个实体的全部数据,就吧下拉框选为目标查询的实体。
几个小点:
* 从 Editor 模板中取得 FetchRequest 的时候必须从 ManagedObjectModel 中取。
构建的 CoreDataStack 类中只应该有 ManagedContext 是 Public 的,其余的都应该是 Private。
NSManagedObjectModel.fetchRequestTemplateForName()
的参数必须跟 Editor 中的保持一致。
NSFetchRequest 神奇の存在
在 CoreData 框架中,NSFetchRequest 就像一把多功能的瑞士军刀,你可以批量获取数据,可以获取单个数据,可以获取最大最小、平均值等、
那么他是如何实现这些的呢,FR 有一个property叫做 resultType
,默认值是 NSManagedResultType
:
NSManagedObjectResultType
:默认值,返回批量的 Managed Object 对象NSCountResultType
: 类型如其名,返回 ManagedObjects.countNSDictionaryResultType
: 返回不同的计算类型,稍后补充NSManagedObjectIDResultType
: 返回特殊的标记,而不是真实的对象,其实这个有点儿像 hashCode 的意思
NSCountResultType 实现 count 计数
在获取了 FR 之后,需要给 FR 添加 predicate,predicate 在创建的时候支持 key path,比如:
lazy var cheapVenuePredicate: NSPredicate = { var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$") return predicate }()
上面代码中的 priceInfo.priceCategory 就是一个应用。
func populateCheapVenueCountLabel() { // $ fetch request let fetchRequest = NSFetchRequest(entityName: "Venue") fetchRequest.resultType = .CountResultType fetchRequest.predicate = cheapVenuePredicate do { let results = try coreDataStack.context.executeFetchRequest(fetchRequest) as! [NSNumber] let count = results.first!.integerValue firstPriceCategoryLabel.text = "\(count) bubble tea places" } catch let error as NSError { print("Could not fetch \(error), \(error.userInfo)") } }
这个方法使用上面的 LazyLoading 的iVar - cheapVenuePredicate 作为 predicate,来做数据查询。
这里指明了 fetchRequest.resultType
= NSCountResultType
,所以结果会返回一个包含了一个 NSNumber
的 NSArray
。当然这个 NSNumber 是一个 NSInteger,它就是那个count。
除了上面的一种执行 executeFetchRequest
的方法获取Count的方法之外,还可以直接调用 context 的countForFetchRequest
方法来获取Count:
func populateExpensiveVenueCountLabel() { // $$$ fetch request let fetchRequest = NSFetchRequest(entityName: "Venue") fetchRequest.resultType = .CountResultType fetchRequest.predicate = expensiveVenuePredicate var error: NSError? let count = coreDataStack.context.countForFetchRequest(fetchRequest, error: &error) if count != NSNotFound { thirdPriceCategoryLabel.text = "\(count) bubble tea places" } else { print("Could not fetch \(error), \(error?.userInfo)") } }
上面的代码中,使用的错误处理不是像之前使用的 try-catch
结构,而是使用 iOS SDK 中常见的 error 的结构,这是因为 countForFetchRequest
方法的第二个参数是一个 *NSError 类型,需要将一个 error 对象的指针传递进去。使用:
coreDataStack.context.countForFetchRequest(fetchRequest, error: &error)来获取查询结果的 count。
DictionaryResultType 实现计算逻辑
前面说了,NSFetchRequest 可以左好多事情,这里包括了一些计算的逻辑。
对于某些需求,比如对查询的结构进行一些SUM、MIN、MAX这样的常见操作,常见一些低效率的代码把所有的数据全部查询出来,然后在程序中使用 For 循环来进行筛选,这样做又 Naive 又低效。
代码如下:
func populateDealsCountLabel() { //1 像之前一样普通的创建 NSFetchRequest,但是 resultType 指定为 .DictionaryResultType let fetchResult = NSFetchRequest(entityName: "Venue") fetchResult.resultType = .DictionaryResultType //2 创建一个 NSExpressionDescription 对象去请求 SUM,而且给它一个 name 标示“sumDeals”,在resultResults中就会有这个 name 标识的返回结果 let sumExpressionDesc = NSExpressionDescription() sumExpressionDesc.name = "sumDeals" //3 上面仅仅给了 ExpressionDescription 一个name标示,但是只是一个String而已,真正让它清楚自己要做sum求和需要给ExpressionDesc对象的这个 .expression 对象做配置: //初始化一个 NSExpression 对象,function写上“sum”,还有好多,使用 command 键按进去方法描述下面一大堆,后面的 argument 参数指明对查询出来的结果的 specialCount 来进行逻辑计算。 sumExpressionDesc.expression = NSExpression(forFunction: "sum:", arguments: [NSExpression(forKeyPath: "specialCount")]) //指定计算结果的数据类型 sumExpressionDesc.expressionResultType = .Integer32AttributeType //4 配置好了 NSExpressionDescription 对象之后,将配置好的它 set 为 NSFetchRequest 对象的 .propertiesToFetch(看见没这里是ties,意思要接受数组,而且可以配置好多个,配置多个就返回多个喽~) fetchResult.propertiesToFetch = [sumExpressionDesc] //5 司空见惯的查询,看从 resultDic 中取得查询结果的那个 [sumDeals] 就是前面 NSExpressDescription.name。 do { let results = try coreDataStack.context.executeFetchRequest(fetchResult) as! [NSDictionary] let resultDic = results.first! let numDeals = resultDic["sumDeals"] numDealsLabel.text = "\(numDeals!) total deals" } catch let error as NSError { print("Could not fetch \(error), \(error.userInfo)") } }
ManagedObjectIDResultType 查询结果的唯一标示
四种类型前面已经说了三种,接下来的一种就是 ManagedObjectIDResultType
,这种查询类型会返回查询结果的一个特殊标志,一种 universal identifier 每一个 ManagedObject 对应着一个特殊的 ID。
之前笔者认为它像 hashCode 但是明显又不一样,因为即便是两个内容相同的 ManagedObjcet,他们的 ID 也都是不一样的,但是 HashCode 确应该是一样的。
iOS 5 的时候取得 NSManagedObjectID 是线程安全的,但是现在已被弃用,但是有更好的并发模型提供给我们使用,以后会有 CoreData 与多线程并发。
另外提两点:
NSFetchRequest 支持批量返回,可以通过设置
fetchBatchSize
、fetchLimit
和fetchOffset
去配置 Batch 的 FetchRequest。另外可以通过
faulting
来优化内存消耗:fault 是一中占位符,它代表着一个还没有真正从存储层取出到内存的 ManagedObject。另外一重优化内存的方法就是使用 predicate,接下来会写到。
(如果使用了 Editor 配置的 predicate,那么在 Runtime 的时候就不能更改 predicate。)
其实 NSPredicate 不属于 Core Data 框架,它是属于 Foundation 框架中的,更多有关于 NSPredicate 的,可以看 [苹果官方的文档](
https://developer.apple.com/library/prerelease/ios/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html) 。
FetchResults 排序
NSFetchRequest 另外一个神奇的功能是它能把获取的数据进行排序,实现的机制是使用 NSSortDescription
类,而且这个排序的执行时机是在 数据存储层
也就是在 SQLite 层完成的,保证了排序的速度和效率。
案例:需要排序的模块中加入 NSSortDescription
的 lazy Var 如下:
lazy var nameSortDescriptor: NSSortDescriptor = { var sd = NSSortDescriptor(key: "name", ascending: true, selector: "localizedStandardCompare:") return sd }() lazy var distanceSortDescription: NSSortDescriptor = { var sd = NSSortDescriptor(key: "location.distance", ascending: true) return sd }()
第一个 NSSortDescription 按照姓名来进行排序,排序的比较方法选择了 String 的 localizedStandardCompare:
。
第二个 NSSortDescription 按照 location.distance
进行排序。
ascending 参数表示是否要升序,true -> ascending
,false -> descending
。
注意:
在 Core Data 框架之外,NSSortDescriptor 支持基于 Block Closure 的 Comparator,这里我们用的是一个 selector。其实在 Core Data 框架内是不允许使用 Comparator 的方法来定义排序的。
同样的,供给 Core Data 使用的 NSPredicate 也是不允许使用任何基于 Block 的 API。
上面两点为什么呢?因为前面说了排序发生在数据存储层,也就是在SQLite查询的时候完成的,Block 的方式不能有效组成一个 SQLite 查询语句。
localizedStandardCompare
是什么,当你对用户看到的那些字符串进行排序的时候,Apple 都建议传递 localizedStandardCompare
来当做排序的规则来对当前字符串进行排序。
如果要某个 SortDescriptor 的逆向排序,可以调用它的 .reversedSordDescriptor
取得。
nameSortDescriptor.reversedSortDescriptor as? NSSortDescriptor
配置好了 SortDescription 之后,将 NSFetchRequest 的 sortDescriptors 属性设置为包含了 SortDescription 的数组:
fetchRequest.sortDescriptors = [sr]
另外:Core Data 中异步查询
- Core Data 简单查询、
- Core Data 下简单联合查询例子
- Core Data 分页查询
- ios简单使用core data
- ios简单使用core data
- iOS-简单使用core data
- ios简单使用core data
- core data CRUD简单操作
- iOS Core Data 简单封装
- Core Data 的简单使用
- iOS Core Data简单演练
- core data查询数据库NSEntityDescription使用
- core data 查询条件 NSPredicate使用
- Core Data 多表连接及查询
- IOS SWIFT CORE DATA 储存,查询,
- iOS:Core Data 中的简单ORM
- core data
- Core Data
- Android6.0的权限系统
- iOS UITextField的使用
- 15 3Sum
- SpringMVC + poi 导出excel表格
- 关于Python35爬虫的一些个人想法(我是菜鸟)
- Core Data 简单查询、
- 【Codeforces Beta Round 2C】【计算几何 转化 模拟退火】Commentator problem 求一个点,使得该点到三个圆的视角范围尽可能接近
- iOS 保持界面流畅的技巧
- eclipse8.0项目自动部署到tomcat
- idhttp的socket error # 10054 错误的处理办法
- STL中的谓词
- ecshop 后台增加上传图片项
- QT自定义控件
- 开涛老师的博客汇总 -- Web MVC 开发学习