使用 FRC Swift 3 更改 CoreData 后 TableView 不更新(reloadData)

Posted

技术标签:

【中文标题】使用 FRC Swift 3 更改 CoreData 后 TableView 不更新(reloadData)【英文标题】:TableView doesn't update(reloadData) after CoreData change using FRC Swift 3 【发布时间】:2016-12-23 06:50:24 【问题描述】:

我已经更新了这个问题,因为我发现了这个问题的另一个关键。似乎当我向 CoreData 添加一些内容时,即使我可以打印出 CoreData 保存的对象,tableview 也不会重新加载数据。所以我知道数据是正确的,但是函数 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 永远不会被调用。

还值得注意的是,如果我停止应用程序并重新打开它,表格视图会显示正确数量的单元格和信息。所以看起来数据只在初始构建时加载属性。

我有一个由CoreData 填充的UITableView,并且还使用了FetchedResultsController。我添加了 FRC 委托方法,并尝试强制使用 tableView.reloadData() 方法,但这似乎不起作用。如果我停止构建并重新构建项目,则会显示数据。

这是我正在使用的委托方法:

    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    tableView.beginUpdates()


func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) 

    switch type 
    case .insert:
        tableView.insertRows(at: [newIndexPath!], with: .automatic)
    case .delete:
        tableView.deleteRows(at: [indexPath!], with: .automatic)
    case .update: 
       tableview.reloadData()
    case .move:
        tableView.deleteRows(at: [indexPath!], with: .automatic)
        tableView.insertRows(at: [newIndexPath!], with: .automatic)
    


func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    tableView.endUpdates()

当我回到这个视图时,我想强制 tableview 重新加载它的数据。

ViewwillAppear 方法:

override func viewWillAppear(_ animated: Bool) 
    // load the data

    let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest()
    fetchRequest.predicate = NSPredicate(format:"statement.@sum.amountOwed >= 0")
    let sort = NSSortDescriptor(key: #keyPath(Person.name), ascending: true)
    fetchRequest.sortDescriptors = [sort]
    positiveFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.managedContext, sectionNameKeyPath: nil, cacheName: nil)

    do
     try positiveFetchedResultsController.performFetch()
     catch let error as NSError
        print("Fetching error: \(error), \(error.userInfo)")
    


    let negativFetchRequest: NSFetchRequest<Person> = Person.fetchRequest()
    negativFetchRequest.predicate = NSPredicate(format:"statement.@sum.amountOwed < 0")
    let negativeSort = NSSortDescriptor(key: #keyPath(Person.name), ascending: true)
    negativFetchRequest.sortDescriptors = [negativeSort]
    negativeFetchedResultsController = NSFetchedResultsController(fetchRequest: negativFetchRequest, managedObjectContext: coreDataStack.managedContext, sectionNameKeyPath: nil, cacheName: nil)

    do
        try negativeFetchedResultsController.performFetch()
    catch let error as NSError
        print("Fetching error: \(error), \(error.userInfo)")
    

    positiveFetchedResultsController.delegate = self
    negativeFetchedResultsController.delegate = self

    print("\(positiveFetchedResultsController.fetchedObjects!.count) positive fetch count")
    //print("\(positiveFetchedResultsController.fetchedObjects![0].statement!.count) positive statements count")
    print("\(negativeFetchedResultsController.fetchedObjects!.count) negative fetch count")
    //print("\(negativeFetchedResultsController.fetchedObjects![0].statement!.count) negative statements count")

    tableView.reloadData()

这是我的 cellForRowAt 方法:

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

    let cell = tableView.dequeueReusableCell(withIdentifier: "personCell", for: indexPath) as! PersonTableViewCell

    switch(indexPath.section) 
    case 0:
        //print("this is section 0")
        let person = positiveFetchedResultsController.object(at: indexPath)
        cell.personName.text = person.name
        //print("\(person.name!) is the name")
        //print("\(person.statement!.count) postive person statement count")

        if(person.statement!.count == 0)
            print("default")
            cell.statementAmount.text = "$0.00"
        
        else
            //print("\(person.name!) has \(person.statement!.count) statement count")
            let amountTotal = person.value(forKeyPath: "statement.@sum.amountOwed") as? Decimal
            //print("\(amountTotal!) this is the total")
            cell.statementAmount.text = convertStringToDollarString(amountToConvert: String(describing: amountTotal!))

        

    case 1:

        print("this is section 1")
        //print("\(negativeFetchedResultsController.object(at: [indexPath.row,0])) objects fetched")
        //print("\(indexPath.section) section number")
        //print("\(indexPath.row) row number")

        let person = negativeFetchedResultsController.fetchedObjects![indexPath.row]
        cell.personName.text = person.name

        print("\(person.name!) is the name")
        print("\(person.statement!.count) negative person statement count")

        if(person.statement!.count == 0)
            cell.statementAmount.text = "$0.00"
        
        else
            //print("\(person.name!) has \(person.statement!.count) statement count")
            let amountTotal = person.value(forKeyPath: "statement.@sum.amountOwed") as? Decimal
            print("\(amountTotal!) this is the total")
            cell.statementAmount.text = String(describing: amountTotal!)

            cell.statementAmount.text = convertStringToDollarString(amountToConvert: String(describing: amountTotal!))
        

        cell.backgroundColor = Styles.redColor();

        let bgColorView = UIView()
        bgColorView.backgroundColor = Styles.darkRedColor()
        cell.selectedBackgroundView = bgColorView

    default: cell.personName.text = "hello"
    
    return cell

【问题讨论】:

只要试试这个 viewwillappear() 并调用你的 table reloaddata() 方法,当你从任何其他控制器回来时,你的 tableview 会重新加载 我试过了,还是不行。我认为这是因为 FRC 正在处理 tableview 数据。 当从任何其他控制器返回时 viewwillappear() 方法必须调用所以我建议它。 我用 ViewWillAppear 方法更新了这个问题,所以你可以看到它是如何被调用的,但它仍然不起作用。 tableView.reloadData() 这个工作与否? 【参考方案1】:

也许试试这个:

override func viewDidAppear(_ animated: Bool) 
    super.viewDidAppear(animated)
    self.tableView.reloadData()

【讨论】:

【参考方案2】: 为此,您只需在调用表 reloadData 之前在 viewWillAppear 函数中添加 fetchedResultsController.delegate = nil。

override func viewWillAppear(_ animated: Bool) 
super.viewWillAppear(animated)
fetchedResultsController.delegate = nil
self.tableView.reloadData()

【讨论】:

以上是关于使用 FRC Swift 3 更改 CoreData 后 TableView 不更新(reloadData)的主要内容,如果未能解决你的问题,请参考以下文章

swift中自定义NSManagedObject类核心数据的问题

如何在 Swift 4 中使用 FetchedResultsController 获取 DateSectionTitles

使用 swift 3 更改解析推送通知

获取结果控制器在运行时不更新表

我正在使用 FRC 在我的 tableview 上显示随机对

如何使用 Swift 3 添加或更改 UIActivityViewController 到我的函数