摘要:当Swift迅速崛起、并渐渐取代oc成功iOS开发的首选语言的时候,Swift的相关框架也是如雨后春笋般冒了出来。RxSwift作为响应式编程的框架。既能完美兼容Swift,又能强健项目架构。很强大。
前段时间,公司也是用RxSwift的架构重构了公司项目。RxSwift虽然语法简洁精炼,可以很大程度上减少代码数量。但其中也存在一些坑,也不知是自己理解不到位还是确实是坑。在此记录下来。避免以后遇到不知所措
-
UITableView的左滑删除
-
场景描述:
tableView的DataSource是用RxSwift双向绑定的,row的点击也是通过RxSwift来监听的。但我设置tableView的代理给ViewController(控制器),并实现左滑删除的代理时。发现该代理不起作用。
有区别的主要代码如下
/// 声明一个可被观察的数组
var arr = Variable<[XYJPersonMsg]>([])
// 绑定数据源
_ = arr.asObservable().bind(to: tableView.rx.items(cellIdentifier: XYJPersonMsgCell.cellIdentifi, cellType: XYJPersonMsgCell.self)) { row, element, cell in
cell.model = element
// 隐藏mj_footer
self.tableView.mj_footer.isHidden = self.tableView.mj_footer.frame.origin.y <= self.tableView.frame.maxY
}
// 设置代理
tableView.rx.setDelegate(self).disposed(by: disposeBag)
-
解决问题:
将该控制器中的RxSwift实现方式改成常用的设置代理的方式实现
有区别的主要代码如下:
var arr = [XYJPersonMsg]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return self.arr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell: XYJPersonMsgCell = tableView.dequeueReusableCell(withIdentifier: XYJPersonMsgCell.cellIdentifi) as? XYJPersonMsgCell ?? XYJPersonMsgCell.init(style: .default, reuseIdentifier: XYJPersonMsgCell.cellIdentifi)
cell.model = self.arr[indexPath.row]
// 隐藏mj_footer
self.tableView.mj_footer.isHidden = self.tableView.mj_footer.frame.origin.y <= self.tableView.frame.maxY
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = XYJPersonDetailVC()
vc.title = "个人消息"
vc.personModel = self.arr[indexPath.row]
// 更新阅读状态
self.arr = self.arr.enumerated().map({ (index,model) -> XYJPersonMsg in
if indexPath.row == index {
model.read_flag = 2
}
return model
})
tableView.reloadData()
self.navigationController?.pushViewController(vc, animated: true)
}
公共的代理代码
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteAction = UITableViewRowAction.init(style: .default, title: " ", handler: { (action, indexPath) in
print("删除")
let personModel = self.arr[indexPath.row] as XYJPersonMsg
self.deleteMsgStatus(parameters: ["id": personModel.id ?? 0,"read_flag": "3"], row: indexPath.row)
})
deleteAction.backgroundColor = UIColor.backgroundColor
let cancleACtion = UITableViewRowAction.init(style: .default, title: " ", handler: { (action, indexPath) in
print("取消")
tableView.reloadData()
})
cancleACtion.backgroundColor = UIColor.backgroundColor
return [deleteAction, cancleACtion]
}
-
UITextField的循环监听
- 场景描述: UITextField一开始不能输入,当UITextField赋值后,可以改变UITextField的内容
主要实现如下:
设置UITextField的enable为false
首先将UITextField的text绑定到VM的textValue上。
当设置UITextField的text的值得时候,再设置textValue的值
// 主要代码代码如下
realNameView.cardField.field.rx.text.orEmpty.asObservable().bind(to: vm.IDCardNumValue).disposed(by: disposeBag)
self.realNameView.cardField.field.rx.text.orEmpty.asObservable().bind(to: self.vm.IDCardNumValue).disposed(by: self.disposeBag)
self.vm.IDCardNumValue.asObservable().subscribe(onNext: { (idno) in
self.realNameView.cardField.field.text = idno
}).disposed(by: self.disposeBag)
self.vm.IDCardNumValue.value = idno
这样会出现当你赋值完后,再输入的时候会出现输一个值,UITestField里面会出现几个相同的值,比如。输入一个a,UITestField里面会出现好多个a
改进:
设置UITextField的enable为false
首先将UITextField的text绑定到VM的textValue上。
监听textValue并设置UITextField的text的值得时候,再设置textValue的值
// 主要代码如下
realNameView.cardField.field.rx.text.orEmpty.asObservable().bind(to: vm.IDCardNumValue).disposed(by: disposeBag)
self.realNameView.cardField.field.rx.text.orEmpty.asObservable().bind(to: self.vm.IDCardNumValue).disposed(by: self.disposeBag)
self.vm.IDCardNumValue.asObservable().take(2).subscribe(onNext: { (idno) in
self.realNameView.cardField.field.text = idno
}).disposed(by: self.disposeBag)
self.vm.IDCardNumValue.value = idno
-
按钮的多次监听
- 场景描述: UI界面的View会刷新(创建->移除->重新创建),在这个过程中,按钮的点击事件会多次绑定到vm上。当绑定了几次之后,再点击按钮的时候,就会连续发出好几个点击事件
// 设置表单数据,以及表单中事件绑定
func setSubmitForm(loginFields: [XYJMobilSuanhuaLoginField]) {
self.loginView.logFieldDatas = loginFields
// 设置手机号码
loginFields.forEach({ (loginField) in
if loginField.name == "phoneNo" {
self.vm.phoneNo.value = loginField.value ?? ""
}
})
self.btnTapbind()
self.countdown()
// 确定登录类型后再进行按钮高亮处理
self.vm.authenBtnBind()
self.formFieldbind()
// 提交按钮高亮绑定(要在 authenBtnBind()后,再设置)
self.vm.authenBtnEnable?.asObservable().bind(to: self.loginView.submitBtn.rx.enabled).disposed(by: self.vm.disposeBag!)
self.loginView.submitBtn.rx.tap.bind(to: self.vm.authenBtnTap!).disposed(by: self.vm.disposeBag!)
self.vm.authenTapResult?.subscribe(onNext: { (formResult) in
let result = self.detailForm(result: formResult)
if result.0 {
self.submitform(parameters: result.1)
}
}).disposed(by: self.vm.disposeBag!)
}
改进:
在按钮创建,按钮点击事件绑定前,先把前一次绑定的资源释放
// 代码如下
// 设置表单数据,以及表单中事件绑定
func setSubmitForm(loginFields: [XYJMobilSuanhuaLoginField]) {
self.loginView.logFieldDatas = loginFields
// 设置手机号码
loginFields.forEach({ (loginField) in
if loginField.name == "phoneNo" {
self.vm.phoneNo.value = loginField.value ?? ""
}
})
self.btnTapbind()
self.countdown()
// 确定登录类型后再进行按钮高亮处理
self.vm.authenBtnBind()
self.formFieldbind()
// 资源释放变量也重新创建
self.vm.disposeBag = DisposeBag()
// 提交按钮高亮绑定(要在 authenBtnBind()后,再设置)
self.vm.authenBtnEnable?.asObservable().bind(to: self.loginView.submitBtn.rx.enabled).disposed(by: self.vm.disposeBag!)
self.loginView.submitBtn.rx.tap.bind(to: self.vm.authenBtnTap!).disposed(by: self.vm.disposeBag!)
self.vm.authenTapResult?.subscribe(onNext: { (formResult) in
let result = self.detailForm(result: formResult)
if result.0 {
self.submitform(parameters: result.1)
}
}).disposed(by: self.vm.disposeBag!)
}