Swift — 4 —核心数据—第6部分,将NSFetchResultController与UITableView一起使用
如果您想进行完整的iOS培训,可以通过以下详细信息与我联系,我会使用目标C或Swift提供实时iOS应用培训
skype:alok.upadhyay32
邮件:meiosdose@gmail.com
应用程式:+ 91–7838552946
您好,希望您一切都好。 在这一部分中,我们将讨论NSFetchResultController( NSFRC )。 我建议您也阅读之前有关核心数据的教程:
基本
简单的应用程序
核心数据单例
使用核心数据进行单元测试
核心数据迁移
NSFetchResultController
- 当需要获取 , 插入 , 更新和删除核心数据并且需要更新用户界面(如UITableView和UICollectionView)时,可以使用NSFetchResultController。
- 每次在托管对象上下文中对托管对象模型执行插入,更新或删除操作时, NSFRC都会提供委托回调 。
- NSFRC提供了performFetch()方法,该方法返回NSManagedObject模型的数组。 这个NSManagedObject模型数组与UITableViewDelegate和UITableViewDataSource方法作为提要数组一起很好地工作。
- NSFRC仅适用于核心数据。
请从这里下载启动项目
请输入☕和开始代码–
FetchResultController的基本初始化包含以下步骤:
- NSManagedObjectContext —一个管理对象上下文,NSManagedObjectContext
- NSFetchRequest —提取请求,其中包含有关要从核心数据存储中提取哪个实体的信息。
- NSSortDescriptor —用于按升序或降序排列结果的排序描述符。
- 在表视图部分中显示的可选部分名称 。
- 缓存名称 ,如果您有一个只读数据集,则NSFetchResultController会在第一时间从存储中读取/读取数据。 下一次提取将使用缓存自动获取数据。
- 显然是一个NSFetchedResultsController类。
- 一个负责获取诸如插入,更新,删除之类的核心数据操作的回调的委托 。
初始化
请牢记所有这些要点,以便打开入门项目并在CoreDataManager类中的代码下面复制粘贴:
懒惰的var fetchedResultsController:NSFetchedResultsController = {
//初始化提取请求
让appDelegate = UIApplication.shared.delegate为! AppDelegate
/ *在使用Core Data进行任何操作之前,需要一个托管对象上下文。 * /
让managedContext = CoreDataManager.sharedManager.persistentContainer.viewContext
/ *顾名思义,NSFetchRequest是负责从Core Data进行提取的类。
使用init(entityName :)初始化获取请求,将获取特定实体的所有对象。 这是您在此处获取所有Person实体的操作。
* /
让fetchRequest = NSFetchRequest (entityName:“ Person”)
//添加排序描述符
让sortDescriptor = NSSortDescriptor(键:“名称”,升序:false)
fetchRequest.sortDescriptors = [sortDescriptor]
//初始化获取的结果控制器
让fetchedResultsController = NSFetchedResultsController (fetchRequest:fetchRequest,managedObjectContext:managedContext,sectionNameKeyPath:nil,cacheName:nil)
//配置提取的结果控制器
// fetchedResultsController.delegate = self
返回fetchedResultsController
}()
为什么我们在这里使用lazy var?
这是NSFetchedResultsController类的延迟初始化 。 延迟初始化是延迟对象的创建,值的计算或其他一些昂贵的任务(如在对象下 初始化 )的策略
- 托管对象上下文NSManagedObjectContext
- 提取请求NSFetchRequest
- 排序描述符NSSortDescriptor
直到第一次需要持久性容器 。
实施代表
同样,为了获得NSFRC的全部好处,我们还应该在ViewCotroller类中实现NSFetchedResultsControllerDelegate协议的委托方法。 复制粘贴以下ViewController类中的代码:
扩展ViewController:NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_控制器:NSFetchedResultsController ){
/ *首先将调用此委托方法。此方法的名称“ controllerWillChangeContent”指示为表视图编写一些逻辑以启动插入行或删除行或更新行过程。 在beginUpdates方法之后,下一个调用将是:
-(void)控制器:(NSFetchedResultsController *)控制器didChangeObject:(id)anObject atIndexPath :(可空NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath :(可空NSIndexPath *)newIndexPath
* /
tableView.beginUpdates()
}
/ *此委托方法将被称为第二。 该方法将提供有关开始插入,更新,删除或移动的确切操作信息。 枚举NSFetchedResultsChangeType将提供更改类型。
公共枚举NSFetchedResultsChangeType:UInt {
案件插入
案例删除
案例移动
案例更新
}
* /
func控制器(_控制器:NSFetchedResultsController ,didChange anObject:任意,在indexPath:IndexPath ?,类型:NSFetchedResultsChangeType,newIndexPath:IndexPath?){
开关(类型){
案例.insert:
如果让indexPath = newIndexPath {
tableView.insertRows(at:[indexPath],带有:.fade)
}
打破;
案例.delete:
如果让indexPath = indexPath {
tableView.deleteRows(at:[indexPath],带有:.fade)
}
打破;
案例.update:
如果让indexPath = indexPath,则让cell = tableView.cellForRow(at:indexPath){
configureCell(cell,at:indexPath)
}
打破;
case .move:
如果让indexPath = indexPath {
tableView.deleteRows(at:[indexPath],带有:.fade)
}
如果让newIndexPath = newIndexPath {
tableView.insertRows(at:[newIndexPath],带有:.fade)
}
打破;
}
}
/ *最后一次代表通话* /
func controllerDidChangeContent(_控制器:NSFetchedResultsController ){
/ *最终平衡beginUpdates与endupdates * /
tableView.endUpdates()
}
}
其实我们已经快完成了。
现在我们需要在ViewController类中进行一些更改。 让我们一一做:
- 注释掉人数组:
// var people:[NSManagedObject] = []
我们注释掉people数组,因为fetchResultsController将为我们提供特定索引路径处的行数,节数和对象数。 不是很好!
- 更新保存功能如下:
//插入
func save(name:String,ssn:Int16){
让_ = CoreDataManager.sharedManager.insertPerson(name:name,ssn:ssn)
}
- 更新delete(ssn :)功能如下:
func delete(ssn:String){
让_ = CoreDataManager.sharedManager.delete(ssn:ssn)
}
- 更新fetchAllPersons函数,如下所示:
func fetchAllPersons(){/ *此类是fetchedResultsController协议方法的委托* /
CoreDataManager.sharedManager.fetchedResultsController.delegate =自我
做{
/ *在fetchedResultsController上启动performFetch()调用* /
试试CoreDataManager.sharedManager.fetchedResultsController.performFetch()
}抓住{
打印(错误)
}
}
- 更新delete(person :)功能如下:
func delete(person:Person){
CoreDataManager.sharedManager.delete(person:person)
}
- 更新update(name :, ssn :, person🙂功能如下:
func update(name:String,ssn:Int16,person:Person){
CoreDataManager.sharedManager.update(名称:名称,ssn:ssn,人:人)
}
- 如下更新numberOfRowsInSection:
func tableView(_ tableView:UITableView,
numberOfRowsInSection部分:Int)-> Int {
/ * fetchResultController的.section方法返回NSFetchedResultsSectionInfo对象的数组。 由于我们未提供任何板块信息,因此板块* /
警卫让路段= CoreDataManager.sharedManager.fetchedResultsController.sections其他{
返回0
}
/ *获取每个部分的行数* /
让sectionInfo =部分[section]
返回sectionInfo.numberOfObjects}
- 更新cellForRow委托并添加configureCell方法,如下所示:
func tableView(_ tableView:UITableView,
cellForRowAt indexPath:IndexPath)-> UITableViewCell {
让cell = tableView.dequeueReusableCell(withIdentifier:“ Cell”,
用于:indexPath)
configureCell(cell,at:indexPath)
返回单元
}
func configureCell(_ cell:UITableViewCell,at indexPath:IndexPath){
/ *从fetchResultController对象获取托管对象* /
let person = CoreDataManager.sharedManager.fetchedResultsController.object(at:indexPath)//配置单元格
cell.textLabel?.text = person.name
}
最后,您的ViewController类应如下所示:
//
// ViewController.swift
// PersonData
//
//由Alok Upadhyay在18/3/28创建。
//版权所有©2018 Alok。 版权所有。
//导入UIKit
导入CoreDataclass ViewController:UIViewController {@IBOutlet弱var tableView:UITableView!
// var people:[NSManagedObject] = []
@IBAction func addName(_ sender:Any){
让alert = UIAlertController(title:“新名称”,
消息:“添加新名称”,
preferredStyle:.alert)
alert.addTextField(configurationHandler:{(textFieldName)在
textFieldName.placeholder =“名称”
})
alert.addTextField(configurationHandler:{(textFieldSSN)在
textFieldSSN.placeholder =“ ssn”
})
让saveAction = UIAlertAction(title:“ Save”,style:.default){
警卫让textField = alert.textFields ?.
让nameToSave = textField.text else {
返回
}
警卫让textFieldSSN = alert.textFields?[1],
让SSNToSave = textFieldSSN.text else {
返回
}
self.save(名称:nameToSave,ssn:Int16(SSNToSave)!)
self.tableView.reloadData()
}
让cancelAction = UIAlertAction(title:“ Cancel”,
样式:.default)
alert.addAction(saveAction)
alert.addAction(cancelAction)
礼物(警告,动画:真实)
}
//插入
func save(name:String,ssn:Int16){
让_ = CoreDataManager.sharedManager.insertPerson(name:name,ssn:ssn)
}
@IBAction函数func deleteAction(_ sender:Any){
/ *使用标题和消息初始化警报控制器* /
let alert = UIAlertController(标题:“由ssn删除”,消息:“输入ssn”,preferredStyle:.alert)
/ *配置删除操作* /
让deleteAction = UIAlertAction(title:“ Delete”,style:.default){
警卫让textField = alert.textFields?.first,让itemToDelete = textField.text else {
返回
}
/ *传递ssn编号以删除(:)方法* /
self.delete(ssn:itemToDelete)
}
/ *配置取消操作* /
让cancelAciton = UIAlertAction(标题:“取消”,样式:.default)
/ *添加文本字段* /
alert.addTextField()
/ *添加动作* /
alert.addAction(deleteAction)
alert.addAction(cancelAciton)
目前(警告,动画:正确,完成:无)
}
func delete(ssn:String){
让_ = CoreDataManager.sharedManager.delete(ssn:ssn)
}
/ *初始化fetchedResultsController并将self设置为委托,同样您需要实现委托方法* /
func fetchAllPersons(){/ *此类是fetchedResultsController协议方法的委托* /
CoreDataManager.sharedManager.fetchedResultsController.delegate =自我
做{
print(“ 2。NSFetchResultController将开始提取:)”)
/ *在fetchedResultsController上启动performFetch()调用* /
试试CoreDataManager.sharedManager.fetchedResultsController.performFetch()
print(“ 3。NSFetchResultController确实结束了提取:)”)} catch {
打印(错误)
}
}
覆盖func viewWillAppear(_动画:布尔){
super.viewWillAppear(动画)
fetchAllPersons()
}
覆盖func viewDidLoad(){
super.viewDidLoad()
//加载视图后进行其他任何设置,通常是从笔尖进行。
tableView.register(UITableViewCell.self,
forCellReuseIdentifier:“单元格”)
}
func delete(person:Person){
CoreDataManager.sharedManager.delete(person:person)
}
func update(name:String,ssn:Int16,person:Person){
CoreDataManager.sharedManager.update(名称:名称,ssn:ssn,人:人)
}
}扩展ViewController:UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView:UITableView,
numberOfRowsInSection部分:Int)-> Int {
/ * fetchResultController的.section方法返回NSFetchedResultsSectionInfo对象的数组。 由于我们未提供任何板块信息,因此板块* /
警卫让路段= CoreDataManager.sharedManager.fetchedResultsController.sections其他{
返回0
}
/ *获取每个部分的行数* /
让sectionInfo =部分[section]
返回sectionInfo.numberOfObjects}
func tableView(_ tableView:UITableView,
cellForRowAt indexPath:IndexPath)-> UITableViewCell {
让cell = tableView.dequeueReusableCell(withIdentifier:“ Cell”,
用于:indexPath)
configureCell(cell,at:indexPath)
返回单元
}
func configureCell(_ cell:UITableViewCell,at indexPath:IndexPath){
/ *获取托管对象* /
let person = CoreDataManager.sharedManager.fetchedResultsController.object(at:indexPath)//配置单元格
cell.textLabel?.text = person.name
}
func tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath){
/ *获取托管对象* /
让person = CoreDataManager.sharedManager.fetchedResultsController.object(at:indexPath)
/ *初始化警报控制器* /
让警报= UIAlertController(标题:“更新名称”,
消息:“更新名称”,
preferredStyle:.alert)
/ *添加名称文本字段* /
alert.addTextField(configurationHandler:{(textFieldName)在
/ *在文本字段中将名称设置为plaveholder * /
textFieldName.placeholder =“名称”
/ *使用键值编码获取键“名称”的值,并将其设置为UITextField的文本。* /
textFieldName.text = person.value(forKey:“ name”)如? 串
})
/ *添加ssn文本字段* /
alert.addTextField(configurationHandler:{(textFieldSSN)在
/ *在文本字段中将ssn设置为plaveholder * /
textFieldSSN.placeholder =“ ssn”
/ *使用键值编码获取键“ ssn”的值,并将其设置为UITextField的文本。* /
textFieldSSN.text =“ \(person.value(forKey:” ssn“)as?Int16 ?? 0)”
})
/ *配置更新事件* /
让updateAction = UIAlertAction(title:“ Update”,style:.default){
警卫让textField = alert.textFields?[0],
让nameToSave = textField.text else {
返回
}
警卫让textFieldSSN = alert.textFields?[1],
让SSNToSave = textFieldSSN.text else {
返回
}
/ * imp部分,负责更新,将nameToSave和SSn传递给update:方法。* /
self.update(名称:nameToSave,ssn:Int16(SSNToSave)!,人:人为!人)
}
/ *配置删除事件* /
让deleteAction = UIAlertAction(title:“ Delete”,style:.default){
/ *查看删除方法的实现* /
self.delete(person:与as一样的人!)
// / *也从数组中删除人员对象,以便数据源具有正确的数据* /
// self.people.remove(at:(self.people.index(of:person))!)
//
// / *最后重新加载tableview * /
// self.tableView.reloadData()
}
/ *配置取消操作* /
让cancelAction = UIAlertAction(title:“ Cancel”,
样式:.default)
/ *添加所有动作* /
alert.addAction(updateAction)
alert.addAction(cancelAction)
alert.addAction(deleteAction)
/ *最终存在* /
礼物(警告,动画:真实)
}
}扩展ViewController:NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_控制器:NSFetchedResultsController ){
/ *首先将调用此委托方法。此方法的名称“ controllerWillChangeContent”指示为表视图编写一些逻辑以启动插入行或删除行或更新行过程。 在beginUpdates方法之后,下一个调用将是:
-(void)控制器:(NSFetchedResultsController *)控制器didChangeObject:(id)anObject atIndexPath :(可空NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath :(可空NSIndexPath *)newIndexPath
* /
print(“ A。NSFetchResultController controllerWillChangeContent :)”)tableView.beginUpdates()
}
/ *此委托方法将被称为第二。 该方法将提供有关开始插入,更新,删除或移动的确切操作信息。 枚举NSFetchedResultsChangeType将提供更改类型。
公共枚举NSFetchedResultsChangeType:UInt {
案件插入
案例删除
案例移动
案例更新
}
* /
func控制器(_控制器:NSFetchedResultsController ,didChange anObject:任意,在indexPath:IndexPath ?,类型:NSFetchedResultsChangeType,newIndexPath:IndexPath?){
print(“ B。NSFetchResultController didChange NSFetchedResultsChangeType \(type.rawValue):)”)
开关(类型){
案例.insert:
如果让indexPath = newIndexPath {
tableView.insertRows(at:[indexPath],带有:.fade)
}
打破;
案例.delete:
如果让indexPath = indexPath {
tableView.deleteRows(at:[indexPath],带有:.fade)
}
打破;
案例.update:
如果让indexPath = indexPath,则让cell = tableView.cellForRow(at:indexPath){
configureCell(cell,at:indexPath)
}
打破;
case .move:
如果让indexPath = indexPath {
tableView.deleteRows(at:[indexPath],带有:.fade)
}
如果让newIndexPath = newIndexPath {
tableView.insertRows(at:[newIndexPath],带有:.fade)
}
打破;
}
}
/ *最后一次代表通话* /
func controllerDidChangeContent(_控制器:NSFetchedResultsController ){
/ *最终平衡beginUpdates与endupdates * /
tableView.endUpdates()
}
}
每当调用托管对象上下文的保存时,都会触发NSFetchResultController的委托方法。 还有一个定义的顺序,其中将调用这些委托方法:
// 1先调用
func controllerWillChangeContent // 2称为第二
func控制器(_控制器:NSFetchedResultsController ,didChange anObject:任何,在indexPath:IndexPath ?,对于类型:NSFetchedResultsChangeType,newIndexPath:IndexPath?)// 3称为最后
func controllerDidChangeContent
在这一点上,如果我们运行项目,我们应该能够插入,更新,删除和获取记录。
希望您现在可以使用它。 在下一部分中,我们将实现NSFetchResultController的节和缓存。
这是最终的源代码。
在这里,我还写了关于使用NSFetchedResultsController类显示带有源代码的sectionTitle的文章。
如果您想进行完整的iOS培训,可以通过以下详细信息与我联系,我会使用目标C或Swift提供实时iOS应用培训
skype:alok.upadhyay32
邮件:meiosdose@gmail.com
应用程式:+ 91–7838552946