在同一个 UITableView 的不同部分显示多个 NSFetchedResultsController
Posted
技术标签:
【中文标题】在同一个 UITableView 的不同部分显示多个 NSFetchedResultsController【英文标题】:Displaying multiple NSFetchedResultsControllers in different sections of same UITableView 【发布时间】:2016-01-12 14:38:16 【问题描述】:早上好。 在我的应用程序中,我有不同的实体,我想在同一个 TableView 中显示它。 我知道要做到这一点,我需要不同的 NSFetchedResultsController。 当我添加一个对象做第一部分时,没有问题出现,但是当我将一个对象添加到第二部分时,问题就出现了。 这是我正在使用的代码
import UIKit
import CoreData
class MainMenu: UITableViewController, NSFetchedResultsControllerDelegate
/**********/
/** Vars **/
/**********/
lazy var frcAccount: NSFetchedResultsController = self.AccountFetchedResultController()
lazy var frcCar: NSFetchedResultsController = self.CarFetchedResultsController()
let idxAccNew = NSIndexPath(forRow: 0, inSection: 0)
let idxCarNew = NSIndexPath(forRow: 0, inSection: 1)
let idxConfig = NSIndexPath(forRow: 0, inSection: 2)
/**************/
/** IBOutlet **/
/**************/
/***************/
/** IBActions **/
/***************/
/***************/
/** Functions **/
/***************/
// MARK:- NSFetchedResultsController
func AccountFetchedResultController() -> NSFetchedResultsController
let fetchRequest = NSFetchRequest(entityName: Account.entityName)
fetchRequest.fetchBatchSize = 10
let sortDescriptor = NSSortDescriptor(key: "id", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
frcAccount = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: coreDataStack.context,
sectionNameKeyPath: nil,
cacheName: nil)
frcAccount.delegate = self
do
try frcAccount.performFetch()
catch
print("Erro: \(error)")
abort()
return frcAccount
func CarFetchedResultsController() -> NSFetchedResultsController
let fetchRequest = NSFetchRequest(entityName: "Car")
fetchRequest.fetchBatchSize = 10
let sortDescriptor = NSSortDescriptor(key: "plate", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
frcCar = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: coreDataStack.context,
sectionNameKeyPath: nil,
cacheName: nil)
frcCar.delegate = self
do
try frcCar.performFetch()
catch
print("Error: \(error)")
abort()
return frcCar
//MARK:- TableViewDataSource
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
return 3
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
switch section
case 0:
return frcAccount.sections![0].numberOfObjects + 1
case 1:
return frcCar.sections![0].numberOfObjects + 1
default:
return 1
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
if indexPath.section == 0
if indexPath.row == 0
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") //as UITableViewCell
cell!.textLabel?.text = "Nova Conta"
return cell!
else
let cell = tableView.dequeueReusableCellWithIdentifier("CellAccount") as! VC_AccountListTableViewCell
let idx = NSIndexPath(forRow: indexPath.row - 1, inSection: 0)
let object = frcAccount.objectAtIndexPath(idx) as! Account
cell.useAccountInfo(object)
return cell
else if indexPath.section == 1
if indexPath.row == 0
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
cell!.textLabel?.text = "Novo Carro"
return cell!
else
let cell = tableView.dequeueReusableCellWithIdentifier("CellCar") as! VC_CarListTableViewCell
let idx = NSIndexPath(forRow: indexPath.row - 1, inSection: 0)
let object = frcCar.objectAtIndexPath(idx) as! Car
cell.useCarInfo(object)
cell.btnFillUp.tag = indexPath.row - 1
cell.btnService.tag = indexPath.row - 1
return cell
else
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
cell!.textLabel?.text = "Configurações"
return cell!
// MARK: TableViewDelegate
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
if indexPath == idxAccNew || indexPath == idxCarNew || indexPath == idxConfig
return 44
else
if indexPath.section == 0
return 80
else if indexPath.section == 1
return 100
else
return 0
// MARK:- NSFetchedResultsControllerDelegate
func controllerWillChangeContent(controller:NSFetchedResultsController)
tableView.beginUpdates()
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType)
switch(type)
case .Insert:
tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
case .Delete:
tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
default:
return
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
switch (type)
case .Insert:
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
case .Delete:
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
case .Move:
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
case .Update:
tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
func controllerDidChangeContent(controller: NSFetchedResultsController)
tableView.reloadData()
tableView.endUpdates()
func reloadData()
tableView.reloadData()
这样可以吗??我尝试了很多不同的解决方案..
谢谢大家
【问题讨论】:
【参考方案1】:在 tableView 数据源方法中,您正确地将 tableView 的 indexPath
重新映射到相关 FRC 的 indexPath
,同时还调整了额外的第一行,例如:
let idx = NSIndexPath(forRow: indexPath.row - 1, inSection: 0)
(请注意,您必须在其他 tableView 数据源委托方法中使用类似的重新映射,例如,如果您实现 didSelectRowAtIndexPath
)。但是您还需要在 FRC 委托方法中进行反向映射,例如。
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?)
var tvIdx = NSIndexPath()
var newTvIdx = NSIndexPath()
var tvSection = 0
// for the Car FRC, we need to insert/delete rows in table view section 1:
if (controller == self.frcCar)
tvSection = 1
// adjust the indexPaths (indexPath and newIndexPath)
// to add the extra row, and use the correct tableView section:
if let idx = indexPath
tvIdx = NSIndexPath(forRow: idx.row + 1, inSection: tvSection)
if let newIdx = newIndexPath
newTvIdx = NSIndexPath(forRow: newIdx.row + 1, inSection: tvSection)
switch (type)
case .Insert:
tableView.insertRowsAtIndexPaths([newTvIdx], withRowAnimation: .Fade)
case .Delete:
tableView.deleteRowsAtIndexPaths([tvIdx], withRowAnimation: .Fade)
case .Move:
tableView.deleteRowsAtIndexPaths([tvIdx], withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths([newTvIdx], withRowAnimation: .Fade)
case .Update:
tableView.reloadRowsAtIndexPaths([tvIdx], withRowAnimation: .Fade)
那么就不需要在controllerDidChangeContent
中使用reloadData
了:
func controllerDidChangeContent(controller: NSFetchedResultsController)
tableView.endUpdates()
【讨论】:
以上是关于在同一个 UITableView 的不同部分显示多个 NSFetchedResultsController的主要内容,如果未能解决你的问题,请参考以下文章
UITableView 部分标题与 UITableviewCell 重叠并且没有背景颜色
UITableView didSelectRowAtIndexPath ,与部分行中显示的值不同!