使用 RXSwift 构建 UITableView 的步骤
- 构建 Observable 类型的数据源
- 将数据源与 tableView 绑定
- 绑定 tableView 的事件(如:cell 的点击事件)
- 设置 tableView Delegate/DataSource 的代理方法(根据需求,非必要)
准备工作
在我们开始之前,我们需要在项目中集成 RXSwift,具体步骤可参见 RXSwift。成功集成之后,我们需要在要使用 RXSwift 的文件中导入它:
import RxSwift
接着,我们要创建一个 DisposeBag 类型的全局变量(一定要是全局变量):
let disposeBag = DisposeBag()
关于 DisposeBag 的作用: DisposeBag 对于 RX 相当于 ARC 对于 iOS,即它是 RX 管理对象内存的一种方式。
最后,将需要使用的 cell 进行注册:
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
OK,到现在为止,我们已经完成了所有的准备工作。接下来,我们可以根据上面的步骤来构建 tableView 了。
构建 Observable 类型的数据源
首先,我们需要构建 Observable 类型的数据源。至于为什么要构建 Observable 类型的数据,我们可以从 RXSwift 的文档上一探究竟。
它的文档上是这么写的:Every Observable sequence is just a sequence. The key advantage for an Observable vs Swift’s Sequence is that it can also receive elements asynchronously。这句话的意思是说,可观察序列和 Swift 的原生序列本质上是一样的,但它们有一个最主要的不同,那就是可观察序列可以异步接受元素。
通过下面的代码创建 Observable 类型的数据源:
let texts = ["Objective-C", "Swift", "RXSwift"]
let textsObservable = Observable.from(optional: texts)
此时,你用 option 键查看 textsObservable 属性的类型,应该显示的是 Observable
可供使用的数据源已经构建完成,接下来需要将数据源与 tableView 绑定。
将数据源与 tableView 绑定
通过下面代码进行绑定(不要忘记最后的 .disposed(by: disposeBag) ):
textsObservable.bind(to: tableView.rx
.items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) { (row, text, cell) in
cell.textLabel?.text = text
}
.disposed(by: disposeBag)
在绑定方法的闭包中,我们需要定义三个变量,三个变量分别有以下含义:
- 第一个变量为当前cell所处的行数,即:indexPath.row
- 第二个变量为可观察序列在当前行数索引的元素,即:texts[row]
- 第三个变量为当前cell
绑定 tableView 的事件
通过下面代码进行绑定(cell 的点击事件):
tableView.rx.itemSelected.bind { (indexPath) in
print(indexPath)
}
.disposed(by: disposeBag)
同样,不要忘记最后的 disposed 。
到这里,我们就完成了通过 RX 构建一个简单的 tableView 。如果你对 tableView 还有一些自定义的需求,可通过第四步骤完成。
设置 tableView Delegate/DataSource 的代理方法
通过下面的代码设置代理:
tableView.rx.setDelegate(self).disposed(by: disposeBag)
tableView.rx.setDataSource(self).disposed(by: disposeBag)
然后,你就可以实现相关的代理方法来进行自定义了,以设置高度举例:
extension ALGExploreDetailVC: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
注意:如果你不需要使用 UITableViewDelegate/UITableViewDataSource 的委托方法的话,你是可以不写的。
// 不使用 RX 的话,需要实现代理方法
tableView.delegate = self
tableView.dataSource = self
extension ViewController: UITableViewDelegate, UITableViewDataSource {
....
}
// 使用 RX
// 绑定即可,不需写上面的代码
textsObservable.bind(to: tableView.rx
.items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) { (row, text, cell) in
cell.textLabel?.text = "\(text)"
}
.disposed(by: disposeBag)
如果使用 RX 绑定了 tableView ,再使用下面的代码就不对了,我们需使用 RX 设置代理的方法。
tableView.delegate = self
总结
- 使用 RX 可以使代码简洁,易读
- 使用 RX 语句后需调用 .disposed(by: disposeBag) ,释放内存
完整代码
import UIKit
import RxSwift
class TestViewController: UIViewController {
var tableView = UITableView(frame: .zero)
let kCellHeight: CGFloat = 40
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
setupSubviews()
}
}
extension TestViewController {
func setupSubviews() {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.safeEdges(to: view)
//1.创建可观察数据源
let texts = ["Objective-C", "Swift", "RXSwift"]
let textsObservable = Observable.from(optional: texts)
//2. 将数据源与 tableView 绑定
textsObservable.bind(to: tableView.rx
.items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) { (row, text, cell) in
cell.textLabel?.text = text
}
.disposed(by: disposeBag)
//3. 绑定 tableView 的事件
tableView.rx.itemSelected.bind { (indexPath) in
print(indexPath)
}
.disposed(by: disposeBag)
//4. 设置 tableView Delegate/DataSource 的代理方法
tableView.rx.setDelegate(self).disposed(by: disposeBag)
}
}
extension TestViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}