更新FRC后,TableViewController不刷新

时间:2017-02-27 18:44:22

标签: ios swift nsfetchedresultscontroller

在选择NSFetchedResultsController(FRC)中的行时,我的应用程序允许通过segueing到详细视图控制器来更改详细信息。保存更改后,将返回已编辑的行并将其插入FRC。

.update代码在以下switch中触发:

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch type {
    case .update:
        configureCell(cell: tableView.cellForRow(at: indexPath! as IndexPath)!, indexPath: indexPath! as NSIndexPath)
        tableView.reloadRows(at: [indexPath!], with: .automatic)
    case .insert:
        tableView.insertRows(at: [newIndexPath!], with: .automatic)
    case .delete:
        tableView.deleteRows(at: [indexPath!], with: .automatic)
    case .move:
        tableView.moveRow(at: indexPath! as IndexPath, to: newIndexPath! as IndexPath)
    }
}

configureCell()方法是:

func configureCell(cell: UITableViewCell, indexPath: NSIndexPath) {
    var handicap: Float

    let cellIdentifier = "PlayerTableViewCell"

    guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath as IndexPath) as? PlayerTableViewCell else {
            fatalError("The dequeued cell is not an instance of PlayerTableViewCell")
        }

    // Populate cell from the NSManagedObject instance
    guard let player = fetchedResultsController.object(at: indexPath as IndexPath) as? Golfer else {
        fatalError("Unexpected Object in FetchedResultsController")
    }

    let firstName = player.value(forKey: "firstName") as! String?
    let lastName = player.value(forKey: "lastName") as! String?
    let fullName = firstName! + " " + lastName!
    handicap = player.value(forKey: "exactHandicap") as! Float

    cell.playerFullName?.text = fullName

    cell.playerPhoto.image = UIImage(data: player.value(forKey: "photo") as! Data)

    cell.numExactHandicap.text = "\(Int(handicap))"
    cell.numStrokesReceived.text = "\(handicap.cleanValue)"

    print("Object for configuration: \(player)")
}

细胞类定义是:

class PlayerTableViewCell: UITableViewCell {

    //MARK: Properties
    @IBOutlet weak var playerFullName: UILabel!
    @IBOutlet weak var playerPhoto: UIImageView!
    @IBOutlet weak var exactHandicapLabel: UILabel!
    @IBOutlet weak var strokesReceivedLabel: UILabel!
    @IBOutlet weak var numExactHandicap: UILabel!
    @IBOutlet weak var numStrokesReceived: UILabel!

   override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

- 编辑#1 -

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

    // Table view cells are reused and should be dequeued using a cell identifier
    let cell = tableView.dequeueReusableCell(withIdentifier: "PlayerTableViewCell", for: indexPath)

    configureCell(cell: cell, indexPath: indexPath as NSIndexPath)

    return cell
}

我得到的行为在很多方面都是出乎意料的。

  1. 在处理.update代码后,屏幕上的数据不会更新,并保留FRC中的预编辑值。

  2. 只有当我在表格中选择同一行时才会刷新行。即它会显示旧值,但在我再次选择行之前,会再次更改为新值。

  3. 当我第一次选择除第0行以外的任何行时,它会将单元格中的所有值设置为故事板中显示的默认值。但是,在任何情况下,第0行从不在segue之前发生变化。

  4. 非常欢迎任何见解!

    - 编辑#3 [2017年4月20日] -

    我一直在讨论这个问题。核心问题仍然存在 - 在处理.update代码后,屏幕上的数据不会刷新,保留FRC中的预编辑值。

    现在,关键代码段如下所示:

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch type {
        case .update:
            golferView.reloadRows(at: [indexPath!], with: .automatic)
        case .insert:
            golferView.insertRows(at: [newIndexPath!], with: .automatic)
        case .delete:
            golferView.deleteRows(at: [indexPath!], with: .automatic)
        case .move:
            golferView.moveRow(at: indexPath! as IndexPath, to: newIndexPath! as IndexPath)
        }
    }
    
    func configureCell(cell: UITableViewCell, indexPath: NSIndexPath) {
        var handicap: Float
        var player: Golfer
    
        let cellIdentifier = "PlayerTableViewCell"
    
        guard let cell = golferView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath as IndexPath) as? PlayerTableViewCell else {
            fatalError("The dequeued cell is not an instance of PlayerTableViewCell")
        }
    
        // Populate cell from the NSManagedObject instance
        player = fetchedResultsController.object(at: indexPath as IndexPath)
    
        let firstName = player.value(forKey: "firstName") as! String?
        let lastName = player.value(forKey: "lastName") as! String?
        let fullName = firstName! + " " + lastName!
        handicap = player.value(forKey: "exactHandicap") as! Float
    
        cell.playerFullName?.text = fullName
    
        cell.playerPhoto.image = UIImage(data: player.value(forKey: "photo") as! Data)
    
        cell.numExactHandicap.text = "\(Int(handicap))"
        cell.numStrokesReceived.text = "\(handicap.cleanValue)"
    
        print("Object for configuration: \(player). And cell values are = \(String(describing: cell.playerFullName?.text)), \(String(describing: cell.numExactHandicap.text)), \(String(describing: cell.numStrokesReceived.text))")
    }
    

    我已经确认controller()方法正在正确触发并且.update开关正在触发reloadRows。这反过来触发configureCell(),其中来自FRC的返回行的内容是正确的,并且插入到单元格中的值与从FRC返回的值匹配。它只是不会刷新UI。

1 个答案:

答案 0 :(得分:1)

在调查内存使用问题时,我偶然发现了对dequeueReusableCell的重复调用,该问题在修复后解决了我一直遇到的问题。

在我的帖子中,在dequeueReusableCell内调用了configureCell。它也会在configureCell来电中调用override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell之前立即调用。

我现在回到正轨!