两个NSFetchResultControllers,一个TableViewController

时间:2015-06-26 12:53:21

标签: ios swift core-data nsfetchedresultscontroller

我想创建一个包含两个部分的tableView。每个部分将从不同的NSFetchResultController填充。我的数据库中有一个名为“newsItem”的实体。在第一部分中,我想显示前五个 newsItems ,其中一个名为“main_article”的属性等于true。第二部分将是 newsItems

这是我的NSFetchResultControllers

 private lazy var fetchedResultsController: NSFetchedResultsController? = { [unowned self] in
    let fetchRequest = NSFetchRequest(entityName: "NewsItem")
    let context = self.managedObjectContext
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
    fetchRequest.predicate = NSPredicate(format: "main_article = YES")
    fetchRequest.fetchLimit = 5
    let controller = NSFetchedResultsController(fetchRequest: fetchRequest,managedObjectContext: context,sectionNameKeyPath: nil,cacheName: nil)

    controller.delegate = self
    controller.performFetch(nil)

    return controller
}()



private lazy var newsroomFetchedResultsController: NSFetchedResultsController? = { [unowned self] in
    let fetchRequest = NSFetchRequest(entityName: "NewsItem")
    let context = self.managedObjectContext
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
    fetchRequest.fetchBatchSize = 100
    let controller = NSFetchedResultsController(fetchRequest: fetchRequest,managedObjectContext: context,sectionNameKeyPath: nil,cacheName: nil)
    controller.delegate = self
    controller.performFetch(nil)

    return controller
}()

NSFetchResultController委托方法

func controllerWillChangeContent(controller: NSFetchedResultsController) {
    self.tableView.beginUpdates()
}


func controller(controller: NSFetchedResultsController,didChangeObject object: AnyObject,atIndexPath indexPath: NSIndexPath?,forChangeType type: NSFetchedResultsChangeType,
    newIndexPath: NSIndexPath?) {

    switch type {
    case .Insert:
        self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Automatic)
    case .Update:
        self.tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
    case .Move:
        self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
        self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Automatic)
    case .Delete:
        self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
    default:
        return
    }

}

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    self.tableView.endUpdates()
}

TableView委派方法

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 2
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 0 {
            return fetchedResultsController?.fetchedObjects?.count ?? 0
        }else {
            return newsroomFetchedResultsController?.fetchedObjects?.count ?? 0
        }


    }

    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        if section == 1 {
            return (tableView.dequeueReusableCellWithIdentifier("section header") as? UITableViewCell)
        }

        return nil
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

            if let newItem = fetchedResultsController?.fetchedObjects?[indexPath.row] as? NewsItem  where indexPath.section == 0 {

                    if let cell = tableView.dequeueReusableCellWithIdentifier("main cell") as? NewMainTableViewCell where indexPath.row == 0{
                        cell.lblTitle.text = newItem.title
                        return cell

                    }
                    else if let cell = tableView.dequeueReusableCellWithIdentifier("new cell") as? NewTableViewCell{
                            cell.lblTitle.text = newItem.title
                            cell.backgroundColor = UIColor.blackColor()
                            cell.lblTitle.textColor = UIColor.whiteColor()
                            return cell
                    }


            }
            else if let newItem = newsroomFetchedResultsController?.fetchedObjects?[indexPath.row] as? NewsItem where indexPath.section == 1 {
                if let cell = tableView.dequeueReusableCellWithIdentifier("new cell") as? NewTableViewCell {
                    cell.lblTitle.text = newItem.title
                    cell.backgroundColor = UIColor.whiteColor()
                    cell.lblTitle.textColor = UIColor.blackColor()
                    return cell
                }
            }


        return UITableViewCell()
    }

    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        if section == 1 {
            return 30
        }

        return 0
    }

    func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 0.001
    }

    func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        return UIView(frame: CGRectZero)
    }

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        if indexPath.section == 0 && indexPath.row == 0 {
            return UIScreen.mainScreen().bounds.width * 1.1
        }else {
            return 67
        }
    }

当我尝试运行它时,我收到此错误,并且tableview显示为空:

* 2015-06-26 15:33:29.183 Kathimerini [5023:965439] ***断言失败 - [UITableView _endCellAnimationsWithContext:],/ SourceCache / UIKit / UIKit-3347.44 / UITableView.m:1623 *

2015-06-26 15:33:29.183 Kathimerini [5023:965439] CoreData:错误:严重的应用程序错误。在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托中捕获到异常。无效更新:第0节中的行数无效。更新(5)后现有部分中包含的行数必须等于更新前该部分中包含的行数(5),加上或减去数字从该部分插入或删除的行(插入1个,删除0个)并加上或减去移入或移出该部分的行数(0移入,0移出)。 userInfo(null)

1 个答案:

答案 0 :(得分:1)

您的委托方法必须考虑两个获取的结果控制器。在插入/删除等行的委托回调中,您应首先检查

(0,10)

您可以通过首先而不是设置获取的结果控制器的委托来测试您的设置是否按预期工作。

另外,请确保您了解索引路径的含义。主要的FRC将报告,例如要在索引路径(1,10)处插入的新项目,但您必须将其插入{{1}}。 FRC不了解您的部分,因为这是表视图的实现细节。