问题
good morning. In my App, I have different Entities and I want to show it in the same TableView. I know that to do it, I need different NSFetchedResultsController. When I add an object do the first section, no problem appears, but when I add an object to the second, the problem appears. Here is the code the I'm using
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()
}
}
Is it possible to do this?? I have tried lots of different solutions..
Thanks all
回答1:
In the tableView datasource methods, you are correctly remapping the tableView's indexPath to the relevant FRC's indexPath, whilst also adjusting for the additional first row, eg:
let idx = NSIndexPath(forRow: indexPath.row - 1, inSection: 0)
(Note that you will have to use similar remapping in other tableView datasource delegate methods, e.g. if you implement didSelectRowAtIndexPath). But you also need to do the reverse mapping in the FRC delegate methods, eg.
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)
}
}
There is then no need to use reloadData in controllerDidChangeContent:
func controllerDidChangeContent(controller: NSFetchedResultsController) {
tableView.endUpdates()
}
来源:https://stackoverflow.com/questions/34746518/displaying-multiple-nsfetchedresultscontrollers-in-different-sections-of-same-ui