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
协议,有value
和scale
两个变量,但只保存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
增加足够多次,最终Person
的Age
类的初始化在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 "beginUpdates" 和 UICollectionView "performBatchUpdates" 是不是具有相同的行为?