在同一UITableView的不同部分中显示多个NSFetchedResultsControllers [英] Displaying multiple NSFetchedResultsControllers in different sections of same UITableView
问题描述
早上好。
在我的应用程序中,我具有不同的实体,并希望在同一TableView中显示它。
我知道要做到这一点,我需要不同的NSFetchedResultsController。
当我在第一部分中添加对象时,没有出现问题,但是当我在第二部分中添加对象时,出现了问题。
这是我正在使用的代码
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..
谢谢
推荐答案
在tableView数据源方法中,您正确地将tableView的 indexPath
映射到相关FRC的 indexPath
,同时还针对额外的第一行,例如:
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)
(请注意,您必须在其他tableView数据源委托方法中使用类似的重映射,例如,如果实现 didSelectRowAtIndexPath
)。但是,您还需要在FRC委托方法中进行反向映射,例如。
(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)
}
}
则无需在 controllerDidChangeContent
中使用 reloadData
:
func controllerDidChangeContent(controller: NSFetchedResultsController) {
tableView.endUpdates()
}
这篇关于在同一UITableView的不同部分中显示多个NSFetchedResultsControllers的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!