UITableView 协议知识点

两个协议的细节: UITableViewDelegate, UITableViewDataSource, and heightForRowAtIndexPath

在 iOS 开发中,UITableView 无疑是最常使用的控件之一。其几乎被用于所有的 iOS 应用中,API 设计之经典,足以满足大多应用场景并完成许多繁重的任务。作为苹果工具箱中少有的具有两个协议的(UITableViewDelegate 和 UITableViewDataSource)API ,其不仅优秀,同样可以给我们一些有趣的启发。

简单来看,数据源和代理的区别是明显且受欢迎的,数据源提供实际的数据,同时代理负责提供可视化布局以及如何处理用户交互等相关信息。我们都是机智的,深知将内容和布局显示分开是件好事情,并且我们习惯于苹果设计的 API ,同时鼓励同其设计行为保持一致。

但是,令人疑惑的是,有一个方法似乎并不符合这种细节:tableView:heightForRowAtIndexPath: 。在许多情况下,表控件的单个 cell 的高度要取决于其中所展示的数据,这是避无可避的。如果一段数据要消失了,是不是要缩小 cell 使其不再显示?或者可能需要延长 cell 使其适应更长的文本。你需要使用你的模型数据来确定如何计算,如此,作为 UITableViewDelegate 中的方法,必然要混杂相关数据,那么不就同苹果鼓励的模式相违背了么!

当然,实际上开发人员习惯将代理和数据源设置为一个对象,所以这似乎更像一个语义分歧,而不是其他什么。但这并不能解释 tableView:heightForRowAtIndexPath: 作为一个代理中的方法,却需要时常访问底层数据。

这是我的理论。我们都熟悉 tableView:cellForRowAtIndexPath: 方法,其作为 UITableViewDataSource 中的方法,负责根据索引返回有效的 UITableViewCell 实例对象。大多和我交流过的开发人员都会在这个方法中进行需要的配置以及布局,或者是不能放在子类中的一些配置及布局。但是,如果不在该方法中进行,又该在何处呢?

UITableViewDelegate 中有一个鲜为人知的方法 tableView:willDisplayCell:forRowAtIndexPath: 。在 tableView:cellForRowAtIndexPath: 调用后,系统自己会进行一些布局配置,然后在进行实际的屏幕渲染前,调用这个鲜为人知的方法。如果这就是苹果想要我们对 cell 进行相关配置的地方呢?

自从 7、8 个月前,我的同事向我介绍了这个方法后,我便很高兴的开始这样做。就像 tableView:heightForRowAtIndexPath: 方法只负责收集相关区域内对象的实现的实现细节计算出一个有效的高度值一样,我也趋向于使用 tableView:willDisplayCell:forRowAtIndexPath: 来进行视图的一些配置,它们因为各种原因无法放在子类中。如此,tableView:cellForRowAtIndexPath: 的存在就只是声明并初始化一个正确的 UITableViewCell 类型的实例对象,然后该对象会传递给 tableView:willDisplayCell:forRowAtIndexPath: 方法,去进行其他繁琐的配置。

这并不会妨碍我创建表示对象,或者使用其他开发人员多年来提出的好用的设计模式,但是这种分离确实值得注意:一个方法只负责实例化对象,另一个方法负责配置该对象。

也许这只是一个学术练习,也许其中有一些我没有意识到的明显的逻辑问题(如果有,你完全可以在推特上呼喊我)。但是在实际的应用中,我发现我的表视图代码更加整洁,也更加容易理解了,自从我将实例化和配置分别放在 tableView:cellForRowAtIndexPath:tableView:willDisplayCell:forRowAtIndexPath: 方法中后。而这也使得 tableView:heightForRowAtIndexPath: 方法作为 UITableViewDelegate 而不是 UITableViewDataSource 中的方法成了一个明智的决定。

发布了129 篇原创文章 · 获赞 23 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/u011374318/article/details/103691809
今日推荐