在选择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
}
我得到的行为在很多方面都是出乎意料的。
在处理.update
代码后,屏幕上的数据不会更新,并保留FRC中的预编辑值。
只有当我在表格中选择同一行时才会刷新行。即它会显示旧值,但在我再次选择行之前,会再次更改为新值。
当我第一次选择除第0行以外的任何行时,它会将单元格中的所有值设置为故事板中显示的默认值。但是,在任何情况下,第0行从不在segue之前发生变化。
非常欢迎任何见解!
- 编辑#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。
答案 0 :(得分:1)
在调查内存使用问题时,我偶然发现了对dequeueReusableCell
的重复调用,该问题在修复后解决了我一直遇到的问题。
在我的帖子中,在dequeueReusableCell
内调用了configureCell
。它也会在configureCell
来电中调用override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
之前立即调用。
我现在回到正轨!