重用
关于重用
重用是在尝试避免以简单统一的方式填充UITableViews/UICollectionViews的过程中创建的,以避免繁琐、重复的工作。
它使用InstanceReuser
的概念,一个配置器来管理所有类似项目。一旦创建,所有数据都将由InstanceReuser
提供以驱动UI。它还将处理交互和数据库更新。
示例
假设我们需要显示一个人员列表。让我们遵循最常用的模式。
首先,我们创建一些结构来保存数据
class PeopleDatabase {
var people: [Person]
init(people: [Person]) {
self.people = people
}
}
其次,是我们的视图控制器
class PeopleViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
private let cellIdentifier: String = "person.cell.id"
@IBOutlet weak var tableView: UITableView!
var database: PeopleDatabase!
func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return database.people.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let person = database.people[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! PersonCell
cell.nameLabel.text = person.name
cell.emailLabel.text = person.email
// ...
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120.0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let person = database.people[indexPath.row]
let viewController = PersonViewController(person: person)
navigationController?.push(viewController, animated: true)
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
guard editingStyle == .delete else { return }
// delete entry from database
// update table
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// update database
}
}
当您只有一个表格时,这是可以的,但当您有更多屏幕时,它不可扩展并且将需要一些代码重复。
个人笔记
对我来说,我发现我在同一项目中有时缺乏结构的一致性。这意味着每次我回顾代码时都有一个学习过程。
这就是Reuse
要做的事情。拥有一个可重用组件系统,它可以应用于实例,并且可以在整个应用中共享。
让我们修改项目以使用Reuse
。
首先,我们实现数据库协议
extension PeopleDatabase: Section, DataProvider {
// MARK: DataProvider protocol
var objects: [Usable] {
get { return people }
set { people = newValue }
}
func canDeleteObject(at index: ObjectIndex) -> Bool {
return true
}
func canMoveObject(at index: ObjectIndex) -> Bool {
return true
}
}
通过使我们的数据库同时成为DataProvider
和Section
,我们基本上可以说它只有一个部分。
然后我们创建一个可重用实例来配置我们的单元格。
struct PersonReuser: InstanceReuser {
var viewIdentifier: String { return "person.cell.id" }
var height: CGFloat { return 120.0 }
private var person: Person?
private weak var navigationController: UINavigationController?
// We inject a navigation controller to handle our navigation.
// I would prefer injecting some `Navigator` protocol, which will allow easier testing and abstraction, but for simplicity we'll just use this.
init(navigationController: UINavigationController?) {
self.navigationController = navigationController
}
// MARK: InstanceReuser protocol
mutating func setObject(_ object: Usable) {
person = object as? Person
}
func configure(_ reusable: Reusable) -> Bool {
guard let person = person, let cell = reusable as? PersonCell else { return false }
cell.nameLabel?.text = person.name
cell.emailLabel?.text = person.email
return true
}
func select() {
guard let person = person else { return }
let viewController = PersonViewController(person: person)
navigationController?.push(viewController, animated: true)
}
}
现在只剩下一个重构我们的视图控制器以创建一个Reuser
,并让它为我们处理所有事情。
class PeopleViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var database: PeopleDatabase!
private var reuser: Reuser!
func viewDidLoad() {
super.viewDidLoad()
setupReuser()
tableView.passHandling(to: reuser)
}
private func setupReuser() {
reuser = Reuser(dataProvider: database)
let instanceReuser = PersonReuser(navigationController: navigationController)
reuser.register(instanceReuser, forObject: Person.self)
}
}
这样您就完成了。Reuse
将处理其他所有事情。您可以为PersonReuser
添加逻辑,或者完全避免编写它,直接使用提供的通用一个。如果您需要更多控制,您可以实现UITableViewDataSource
和UITableViewDelegate
函数,并且只需使用索引访问您的重用。例如:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
reuser[indexPath].select()
tableView.deselectRow(at: indexPath, animated: true)
}
现在,如果您需要在其他地方使用它,只需重用
即可。无需代码重复。易于维护、更新或替换。
您可以做的还有更多,但我会让您去探索。
希望它对您的帮助和我的一样大。
安装
重用通过CocoaPods提供。要安装,只需将以下行添加到您的Podfile
pod 'Reuse'
作者
Oren Farhan
许可证
重用可遵守MIT许可证。有关更多信息,请参阅LICENSE文件。