iOS Swift教程 Core Data (四)Fetch进阶 上
2015-01-01 11:13
567 查看
前面三节中,我们使用了最简单的方法来保存或获取CoreData中的数据比如:获取所有的领结实例,但是有些时候,你可能想给予fetch更多的掌控,通过这节的学习,你将学会以下知识:
只获取你需要的数据;
使用predicates来优化fetch的结果;
在后台进程中进行fetch操作而不阻塞UI进程;
直接更新persistent store而减少不必要的fetch操作;
转载请注明出处:/article/9358011.html
源代码地址:https://github.com/dnawym/StudySwift/tree/master/CoreData/Bubble%20Tea%20Finder
NSFetchRequest:
前面章节中我们已经学到,NSFetchRequest实例用于从Core Data中获取数据,配置这个类的实例并将其交给NSManagedObjectContext,后后者会帮我们完成后续的工作。构造fetch request的方法有如下四种:
第一种:创建NSFetchRequest的实例和NSEntityDescription的实例,将entity赋值给fetch request
这款应用程序使用从Foursqure得到纽约市内30个珍珠奶茶点作为数据源(json),给据给定的过滤条件在table view中进行显示。
创建fetch request:
打开Model。xcdatamodeld左键按住Add Entity不放,选择弹出对话框中的第二个选项“Add Fetch Request”
这样就创建了我们需要的一个Fetch Request,我们暂时不需要为新创建的fetch request添加其它条件
接下来,我们在ViewController里面使用这个FetchRequest,添加变量的定义
修改viewDidLoad,通过managed object model来获取我们创建的FetchRequest。fetchRequestTemplateForName使用字符串来查找我们使用model editor创建的FetchRequest
获取不同类型的结果:
至此,你可能认为NSFetchRequest这个类是一个很简单的工具,设置一些属性,你就可以得到所需的数据。其实,NSFetchRequest像瑞士军刀一样,有这多种多样的功能。比如:获取一个单独的数据,计算统计结果(平均值、最小值和最大值等等)。
NSFetchRequest有一个名为resultType的属性,我们现在只是用了.Default值,除了这个值还有如下几种:
NSManagedObjectResultType:返回一个managed object(默认值)
NSCountResultType:返回满足fetch request的object数量
NSDictionaryResultType:
NSManagedObjectIDResultType:返回唯一的标示符而不是managed object
计算不同价位商家的数目:
修改FilterViewController.swift,添加最低价位的predicate函数:
添加函数查询最低价位商家的数目并更新到Label上:
对fetch request进行计算:
首先计算deal的和,设置返回值类型是.DictionaryResultType
最后一种返回值类型是.ManagedObjectIDResultType,这种类型的fetch结果返回值是NSManagedObjectID的数组,类似于数据库的主键。
由于每一次fetch,可能返回大量的数据,这样每一个fetch都会消耗大量的内存,接下来我们使用Predicate来限制返回的数据的数量。
为FilterViewController类添加protocol,这样实现了这个protocol的类在用户修改了排序或过滤条件后就会被通知到。
类似的方法,实现其它三种predicate
只获取你需要的数据;
使用predicates来优化fetch的结果;
在后台进程中进行fetch操作而不阻塞UI进程;
直接更新persistent store而减少不必要的fetch操作;
转载请注明出处:/article/9358011.html
源代码地址:https://github.com/dnawym/StudySwift/tree/master/CoreData/Bubble%20Tea%20Finder
NSFetchRequest:
前面章节中我们已经学到,NSFetchRequest实例用于从Core Data中获取数据,配置这个类的实例并将其交给NSManagedObjectContext,后后者会帮我们完成后续的工作。构造fetch request的方法有如下四种:
第一种:创建NSFetchRequest的实例和NSEntityDescription的实例,将entity赋值给fetch request
let fetchRequest1 = NSFetchRequest() let entity = NSEntityDescription.entityForName("Person", inManagedObjectContext: managedObjectContext!) fetchRequest1.entity = entity!第二种:将entity的名称作为参数传递给fetch request,这样就不用显示的构造entity
let fetchRequest2 = NSFetchRequest(entityName: "Person")第三种:使用NSManagedObjectModel来构造fetch request,这一节我们会使用这种方法
let fetchRequest3 = managedObjectModel.fetchRequestTemplateForName("peoperFR")第四种:和第三种方法类似,但是会传递额外的参数给NSManagedObjectModel,这些额外的参数用于优化fetch结果
let fetchRequest4 = managedObjectModel.fetchRequestFromTemplateWithName("peopleFR", substitutionVariables: ["NAME" : "Ray"])珍珠奶茶:
这款应用程序使用从Foursqure得到纽约市内30个珍珠奶茶点作为数据源(json),给据给定的过滤条件在table view中进行显示。
创建fetch request:
打开Model。xcdatamodeld左键按住Add Entity不放,选择弹出对话框中的第二个选项“Add Fetch Request”
这样就创建了我们需要的一个Fetch Request,我们暂时不需要为新创建的fetch request添加其它条件
接下来,我们在ViewController里面使用这个FetchRequest,添加变量的定义
import CoreData
var fetchRequest: NSFetchRequest! var venues: [Venue]!
修改viewDidLoad,通过managed object model来获取我们创建的FetchRequest。fetchRequestTemplateForName使用字符串来查找我们使用model editor创建的FetchRequest
override func viewDidLoad() { super.viewDidLoad() fetchRequest = coreDataStack.model.fetchRequestTemplateForName("FetchRequest") fetchAndReload() }fetchAndReload函数顾名思义,从core data获取数据并刷新table view
//MARK: - 辅助函数 func fetchAndReload() { var error: NSError? let results = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [Venue]? if let fetchResults = results { venues = fetchResults } else { println("Could not fetch \(error), \(error!.userInfo)") } tableView.reloadData() }修改tableView的2个函数numberOfRowsInSection和cellForRowAtIndexPath
func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int { return venues.count } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { var cell = tableView.dequeueReusableCellWithIdentifier("VenueCell") as UITableViewCell let venue = venues[indexPath.row] cell.textLabel!.text = venue.name cell.detailTextLabel!.text = venue.priceInfo.priceCategory return cell }程序执行效果如下:
获取不同类型的结果:
至此,你可能认为NSFetchRequest这个类是一个很简单的工具,设置一些属性,你就可以得到所需的数据。其实,NSFetchRequest像瑞士军刀一样,有这多种多样的功能。比如:获取一个单独的数据,计算统计结果(平均值、最小值和最大值等等)。
NSFetchRequest有一个名为resultType的属性,我们现在只是用了.Default值,除了这个值还有如下几种:
NSManagedObjectResultType:返回一个managed object(默认值)
NSCountResultType:返回满足fetch request的object数量
NSDictionaryResultType:
NSManagedObjectIDResultType:返回唯一的标示符而不是managed object
计算不同价位商家的数目:
修改FilterViewController.swift,添加最低价位的predicate函数:
// 这个NSPredicate用于计算属于最低价格区间的venues数量 lazy var cheapVenuePredicate: NSPredicate = { var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$") return predicate! }()
添加函数查询最低价位商家的数目并更新到Label上:
func populateCheapVenueCountLabel() { let fetchRequest = NSFetchRequest(entityName: "Venue") fetchRequest.resultType = .CountResultType fetchRequest.predicate = cheapVenuePredicate var error: NSError? let result = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [NSNumber]? if let countArray = result { let count = countArray[0].integerValue firstPriceCategoryLabel.text = "\(count) bubble tea pleases" } else { println("Could not fetch \(error), \(error!.userInfo)") } }重载viewDidLoad函数
override func viewDidLoad() { super.viewDidLoad() populateCheapVenueCountLabel() }接下来添加中等价位和高价位商家的数量
lazy var moderateVenuePredicate: NSPredicate = { var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$$") return predicate! }() func populateModerateVenueCountLabel() { let fetchRequest = NSFetchRequest(entityName: "Venue") fetchRequest.resultType = .CountResultType fetchRequest.predicate = moderateVenuePredicate var error: NSError? let result = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [NSNumber]? if let countArray = result { let count = countArray[0].integerValue secondPriceCategoryLabel.text = "\(count) bubble tea pleases" } else { println("Could not fetch \(error), \(error!.userInfo)") } } lazy var expensiveVenuePredicate: NSPredicate = { var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$$$") return predicate! }() func populateExpensiveVenueCountLabel() { let fetchRequest = NSFetchRequest(entityName: "Venue") fetchRequest.resultType = .CountResultType fetchRequest.predicate = expensiveVenuePredicate var error: NSError? let result = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [NSNumber]? if let countArray = result { let count = countArray[0].integerValue thirdPriceCategoryLabel.text = "\(count) bubble tea pleases" } else { println("Could not fetch \(error), \(error!.userInfo)") } }更新viewDidLoad函数
override func viewDidLoad() { super.viewDidLoad() populateCheapVenueCountLabel() populateModerateVenueCountLabel() populateExpensiveVenueCountLabel() }程序filter页面效果如下,低价位商家27家,中等价位2家,高价位1家:
对fetch request进行计算:
首先计算deal的和,设置返回值类型是.DictionaryResultType
func populateDealsCountLabel() { // 创建FetchRequest获取Venue对象并设置返回值类型为DictionaryResultType let fetchRequest = NSFetchRequest(entityName: "Venue") fetchRequest.resultType = .DictionaryResultType // 创建NSExpressionDescription来请求进行总和计算,取名为sumDeals,一会儿就可以通过这个名字 // 从fetch请求返回的字典中找到总和 let sumExpressionDesc = NSExpressionDescription() sumExpressionDesc.name = "sumDeals" // 指定要进行总和计算的字段名-specialCount并设置返回值类型 sumExpressionDesc.expression = NSExpression(forFunction: "sum:", arguments:[NSExpression(forKeyPath: "specialCount")]) sumExpressionDesc.expressionResultType = .Integer32AttributeType // 设置fetchRequest的propertiesToFetch属性为我们构造的sumExpressionDesc告诉fetchRequest // 我们需要对数据进行求和 fetchRequest.propertiesToFetch = [sumExpressionDesc] // 执行fetch request,将返回结果转换为optional字典,使用设置的字段名-sumDeals来索引求和的结果 var error: NSError? let result = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [NSDictionary]? if let resultArray = result { let resultDict = resultArray[0] let numDeals: AnyObject? = resultDict["sumDeals"] numDealsLabel.text = "\(numDeals!) total deals" } else { println("Could not fetch \(error), \(error!.userInfo)") } }
最后一种返回值类型是.ManagedObjectIDResultType,这种类型的fetch结果返回值是NSManagedObjectID的数组,类似于数据库的主键。
由于每一次fetch,可能返回大量的数据,这样每一个fetch都会消耗大量的内存,接下来我们使用Predicate来限制返回的数据的数量。
为FilterViewController类添加protocol,这样实现了这个protocol的类在用户修改了排序或过滤条件后就会被通知到。
protocol FilterViewControllerDelegate: class { func filterViewController(filter: FilterViewController, didSelectPredicate predicate: NSPredicate?, sortDescriptor: NSSortDescriptor?) }添加delegate,选定的NSSortDescriptor和NSPredicate的定义
weak var delegate: FilterViewControllerDelegate? var selectedSortDescriptor: NSSortDescriptor? var selectedPredicate: NSPredicate?修改saveButtonTapped函数和didSelectRowAtIndexPath。当用户点击价格分类cell时,更新selectedPredicate。当用户点击search按钮时,调用代理的filterViewController的函数。
//MARK - UITableViewDelegate methods override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let cell = tableView.cellForRowAtIndexPath(indexPath)! switch cell { case cheapVenueCell: selectedPredicate = cheapVenuePredicate case moderateVenueCell: selectedPredicate = moderateVenuePredicate case expensiveVenueCell: selectedPredicate = expensiveVenuePredicate default: println("default case") } cell.accessoryType = .Checkmark } // MARK - UIButton target action @IBAction func saveButtonTapped(sender: UIBarButtonItem) { delegate!.filterViewController(self, didSelectPredicate: selectedPredicate, sortDescriptor: selectedSortDescriptor) dismissViewControllerAnimated(true, completion:nil) }回到ViewController,实现代理函数
//MARK: - FilterViewControllerDelegate methods func filterViewController(filter: FilterViewController, didSelectPredicate predicate: NSPredicate?, sortDescriptor: NSSortDescriptor?) { fetchRequest.predicate = nil fetchRequest.sortDescriptors = nil if let fetchPredicate = predicate { fetchRequest.predicate = fetchPredicate } if let sr = sortDescriptor { fetchRequest.sortDescriptors = [sr] } fetchAndReload() }程序执行效果如下,在过滤页面选择只显示中等价位的商家:
类似的方法,实现其它三种predicate
lazy var offeringDealPredicate: NSPredicate = { var pr = NSPredicate(format: "specialCount > 0") return pr! }() lazy var walkingDistancePredicate: NSPredicate = { var pr = NSPredicate(format: "location.distance < 500") return pr! }() lazy var hasUserTipsPredicate: NSPredicate = { var pr = NSPredicate(format: "stats.tipCount > 0") return pr! }()更新didSelectRowAtIndexPath函数
//MARK - UITableViewDelegate methods override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let cell = tableView.cellForRowAtIndexPath(indexPath)! switch cell { case cheapVenueCell: selectedPredicate = cheapVenuePredicate case moderateVenueCell: selectedPredicate = moderateVenuePredicate case expensiveVenueCell: selectedPredicate = expensiveVenuePredicate case offeringDealCell: selectedPredicate = offeringDealPredicate case walkingDistanceCell: selectedPredicate = walkingDistancePredicate case userTipsCell: selectedPredicate = hasUserTipsPredicate default: println("default case") } cell.accessoryType = .Checkmark }
相关文章推荐
- iOS Swift教程 Core Data (四)Fetch进阶 下
- iOS Swift教程 Core Data (三)Core Data栈 上
- iOS Swift教程 Core Data (六)单元测试
- iOS Swift教程 Core Data (二)ManagedObject subclass 下
- iOS Swift教程 Core Data (五)NSFetchedResultsController 上
- iOS Swift教程 Core Data (三)Core Data栈 下
- iOS Swift教程 Core Data (五)NSFetchedResultsController 下
- iOS Swift教程 Core Data (二)ManagedObject subclass 上
- iOS Swift教程 Core Data 概述
- iOS Swift教程 Core Data (一)Hello Core Data
- Swift视频教程,Swift培训,Swift千人免费学iOS开发编程语言
- swift的代码教程-ios警告框类(VKAlert)
- swift的代码教程-ios文件管理类(FileOp)
- iOS游戏框架Sprite Kit基础教程——Swift版上册
- Swift视频教程,Swift千人学iOS开发编程语言
- ios新开发语言swift 新手教程
- iOS 8 Metal Swift教程 :开始学习
- iOS 8 Metal Swift 教程(二):3D图形
- iOS应用开发视频教程笔记(十三)Core Data
- Swift教程第二部分: 一个简单的iOS应用