解码后如何恢复 UICollectionViewCell 中的绑定
Posted
技术标签:
【中文标题】解码后如何恢复 UICollectionViewCell 中的绑定【英文标题】:How to restore bindings in UICollectionViewCell after it is decoded 【发布时间】:2016-01-12 22:18:20 【问题描述】:我有一个UICollectionViewCell
的子类。单元在情节提要中以视觉方式设计,包含许多组件,这些组件使用情节提要绑定到 Swift 子类中的变量。
Swift 类仅提供从数据源检索到的 dat 填充组件的逻辑。
例如:
class InfoCollectionViewCell : UICollectionViewCell
@IBOutlet weak var mainPanel : UIView!
@IBOutlet weak var panel1 : UIView!
@IBOutlet weak var firstName : UILabel!
@IBOutlet weak var lastName : UILabel!
@IBOutlet weak var address : UILabel!
etc ...
func setVariousProperties(etc)
firstName.text = ... etc
数据源做通常的事情:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("InfoCell", forIndexPath:indexPath)
if let c : InfoCollectionViewCell = cell as? InfoCollectionViewCell
c.setVariousProperties(...)
我最初只实现了包含“未实现”断言的 decode/encode 方法,但很明显框架偶尔会对类进行编码和解码。我在不保存组件的情况下实现了虚拟编码/解码方法,导致在访问组件时出现 nil 值的可预测问题。
所以看来我要么需要对UICollectionViewCell
子类中的所有控件进行编码和解码,要么必须找到更好的方法。
这似乎是在浪费时间,因为我实际上并不需要(我不认为)保存组件的内容,因为它们无论如何都会被子类重用:我将覆盖组件内容将来自数据源的值。
显然,所有控件都在情节提要中定义。我可以在 init 方法中从情节提要中手动按名称获取它们,但这似乎同样乏味,并且使控件和变量的图形链接变得多余。
有没有更好的办法?
我可以只说“恢复连接”或类似的话吗?
编辑:
在发布问题和添加赏金之间的某个地方,问题停止发生。我现在注意到我的组件的 encode 方法没有被调用。所以出于某种原因,框架决定序列化我的对象并反序列化它们,但现在不是。因此问题没有发生,我无法提供堆栈跟踪。
可以想象,XCode 的一些更新已经解决了这个问题,或者它可能是其他问题。
我显然仍然担心某处潜伏着一些错误。
【问题讨论】:
其他人有这个问题吗?我会很感激 cmets。 【参考方案1】:您不需要对故事板中已布局和连接的任何控件实施编码/解码。这将在运行时进行处理,只要其他所有内容都已与准备使用的 UI 组件正确连接,您将在 collectionView.dequeueReusableCellWithReuseIdentifier
之后返回一个单元格。要检查的事项是:
-
子类在情节提要自定义类部分中指定
reuseIdentifier 被定义为匹配您期望的字符串
所有 IBOutlet 都已连接,并且还应在 IBOutlet var 行旁边的代码中显示连接。
一旦您确定这些是正确的,请尝试打印出组件以检查它们是否仍然为 nil,并在其中放置一些简单的文本以消除任何数据源问题:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("InfoCell", forIndexPath:indexPath)
if let c = cell as? InfoCollectionViewCell
print(c.address)
print(c.firstName)
print(c.lastName)
c.firstName.text = "firstName Test"
c.lastName.text = "lastName Test"
c.address.text = "address Test"
return cell
【讨论】:
当然,现在无法重现。这是一个在执行滚动时在具有 100 个单元格的视图上很容易重现的问题,但在单元格较少的视图上以及在显示的第一个屏幕上则不然。我认为某些东西触发了单元格的序列化。现在困扰我的是那里有一个间歇性错误,因为无论如何您提出的所有建议都必须得到应用,否则我不会让第一个单元格屏幕正常工作。我得到的错误清楚地表明 init(coder) 正在被调用,并且很明显 IBOutlets 在解码后没有被连接。 我希望这是正确的答案。我只是不相信它是。正如我上面所说,编码/解码调用停止发生的原因未知。即使它是某些版本的 ios(或模拟器)中的错误,我也不能确定它是否已在所有设备上修复。听起来最好的策略是安全起见并为所有组件实现解码和编码。 当您说实现编码/解码方法时,您的意思是init(coder decoder: NSCoder)
还是您在谈论不同/自定义的东西?如果它是 init,我希望仅在创建/分配新实例时调用它,而不是每次单元格出列并由 UICollectionview 使用时调用。出队的要点是防止过度释放,然后重新分配基本相同的单元格。我从来不需要在单元格上实现编码/解码方法,但也许我很幸运。
是的 - 我的意思是 init(coder decoder: NSCoder)
和 encodeWithCoder(_ aCoder: NSCoder)
。我确信我看到这些被调用了,我当然没有直接调用它们。我突然想到,如果我的应用程序保存状态(我确实保存)间接引用了一个组件,那么它可能会发生。但这似乎不太可能。必须有某种类型的反向引用。
我希望所有组件都调用init(coder decoder: NSCoder)
,因为它们需要从已编译的 Nib/Storyboard 文件中实例化,但我不希望您需要覆盖它,除非您正在做一些非常自定义的事情(我什至想不出一个很好的例子,但也许如果你是一个控件的子类)。我不希望在出队时调用它,因为除了第一次出现之外,单元格已经被实例化并在队列中等待。以上是关于解码后如何恢复 UICollectionViewCell 中的绑定的主要内容,如果未能解决你的问题,请参考以下文章