两个 NSFetchResultControllers ,一个 TableViewController
Posted
技术标签:
【中文标题】两个 NSFetchResultControllers ,一个 TableViewController【英文标题】:Two NSFetchResultControllers , One TableViewController 【发布时间】:2015-06-26 12:53:21 【问题描述】:我想创建一个包含两个部分的 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】:您的委托方法必须考虑到两个获取的结果控制器。在插入/删除等行的委托回调中,您应该首先检查
if controller == self.fetchedResultsController
// modify section 1
else
// modify section 0
您可以通过首先不设置获取结果控制器的委托来测试您的设置是否按预期工作。
另外,请确保您了解索引路径的含义。主要 FRC 将报告例如要在索引路径(0,10)
处插入一个新项目,但您必须将其插入到(1,10)
处。 FRC 不知道您的部分,因为这是您的表视图的实现细节。
【讨论】:
以上是关于两个 NSFetchResultControllers ,一个 TableViewController的主要内容,如果未能解决你的问题,请参考以下文章
写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果两个整数由键盘输入。