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模型数组UITableViewDelegateUITableViewDataSource方法作为提要数组一起很好地工作。
  • 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

Interesting Posts