在同一UITableView的不同部分中显示多个NSFetchedResultsControllers [英] Displaying multiple NSFetchedResultsControllers in different sections of same UITableView

查看:49
本文介绍了在同一UITableView的不同部分中显示多个NSFetchedResultsControllers的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

早上好。
在我的应用程序中,我具有不同的实体,并希望在同一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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆