RAC和RxSwift

使用RxSwift所遇到的坑

2017-10-24  本文已影响0人  jamalping

摘要:当Swift迅速崛起、并渐渐取代oc成功iOS开发的首选语言的时候,Swift的相关框架也是如雨后春笋般冒了出来。RxSwift作为响应式编程的框架。既能完美兼容Swift,又能强健项目架构。很强大。
前段时间,公司也是用RxSwift的架构重构了公司项目。RxSwift虽然语法简洁精炼,可以很大程度上减少代码数量。但其中也存在一些坑,也不知是自己理解不到位还是确实是坑。在此记录下来。避免以后遇到不知所措

  1. 场景描述:
    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)
  1. 解决问题:
    将该控制器中的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]
    }
  1. 场景描述: 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
  1. 场景描述: 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!)
    }
上一篇下一篇

猜你喜欢

热点阅读