UITableView "cellForRowAt: indexPath" 偶尔在 Core Data 属性上调用 "init?(coder aDecoder: NSCo

Posted

技术标签:

【中文标题】UITableView "cellForRowAt: indexPath" 偶尔在 Core Data 属性上调用 "init?(coder aDecoder: NSCoder)"【英文标题】:UITableView "cellForRowAt: indexPath" Occasionally Calling "init?(coder aDecoder: NSCoder)" on Core Data Attribute 【发布时间】:2018-08-01 17:34:27 【问题描述】:

我有一个核心数据实体Person,其可转换属性age 类型为Age

final class Person: NSManagedObject 
    @NSManaged public fileprivate(set) var age: Age

Age采用NSCoding协议,有valuescale两个变量,但只保存value

class Age: NSObject, NSCoding 

    @objc public var value: Double
    public var scale = 1.0

    override public var description: String 
        return "\(scale * value)"
    

    func encode(with aCoder: NSCoder) 
        aCoder.encode(value, forKey: #keyPath(value))
    

    public convenience required init?(coder aDecoder: NSCoder) 
        self.init(value: aDecoder.decodeDouble(forKey: #keyPath(value)))
    

    init(value: Double) 
        self.value = value
    


我在UITableViewCell 中显示Person 实例的age。此实例 (person) 的年龄值为 10.0,即person.age.value = 10.0,因此当通过UIStepper 以编程方式将比例更改为scale = 2.0 时,UITableViewCell 显示20.0(即@987654340 @)。

然而,我发现如果我将UIStepper 增加足够多次,最终PersonAge 类的初始化在tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 方法期间被调用,该方法在给定的IndexPath 处返回Person 的实例。这显然会导致调用Age 类中的init?(coder aDecoder: NSCoder) 方法,从而将scale 属性的值重置为1。

为什么会发生这种情况,请问有没有办法解决这个问题?我希望scale 属性的值始终保持在@987654351 上设置的值@。

感谢您对此事的任何帮助。

编辑

indexPath 处的给定person 可以通过以下方式获得:

private var people: [Person] 
    return Array(database.people).sortedArray(using: Person.defaultSortDescriptors)


private func person(at indexPath: IndexPath) -> Person 
    return people[indexPath.item]

【问题讨论】:

This obviously causes the init?(coder aDecoder: NSCoder) method within the Age class to be called: Age 是用什么编码器初始化的?我看不出这里的可变形性如何。是关于持续的年龄,如果重新加载一个单元格,规模就会丢失?每次 UIStepper 更改并重新加载/稍后向 Age 提供所需值时,编码器是否应该存储/保留 Age? 如何获得人员数组?能否提供cellForRowAtIndexPath:方法的源代码? age 属性的初始化可能是由于将您的 Person 对象变为错误而引起的。进一步访问age 属性将通过init?(coder aDecoder: NSCoder) 从存储中恢复它。 @cocavo 感谢您的帮助。我已经介绍了如何从存储在 Database 实体中的一组 People 中选择 person 据我了解,每次访问时都会生成people 数组。这就是您在 cellForRowAtIndexPath: 方法中获得新创建的 Person 对象的原因。尝试只生成一次people 数组并将其存储为视图控制器的属性。我想它应该对你有帮助。 【参考方案1】:

您的people 属性是computed property,这意味着您每次通过people[indexPath.item] 访问它时都会获得一个新的人员数组。因此,每次调用 func person(at:) 时,您都会初始化一个新的 Person 实例,我猜是 tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

通过更改步进值来测试这一点,然后使单元格从屏幕上消失并返回到同一个单元格。那么年龄将被重置。

只需让你的人员数组像这样存储属性。

private var people: [Person] = Array(database.people).sortedArray(using: Person.defaultSortDescriptors)

【讨论】:

以上是关于UITableView "cellForRowAt: indexPath" 偶尔在 Core Data 属性上调用 "init?(coder aDecoder: NSCo的主要内容,如果未能解决你的问题,请参考以下文章

动画 contentInset 到 UITableView 也动画行的子视图的框架

关于collectionview中的cellfor 代理方法没调用问题

从表格视图单元格内的文本字段中获取文本

带有 UIView 子类的 UITableViewCell 在单元格上创建多个图层

小心UITableView中的"数组越界Crash"

UITableView "beginUpdates" 和 UICollectionView "performBatchUpdates" 是不是具有相同的行为?