美文网首页RAC和RxSwift
使用RxSwift所遇到的坑

使用RxSwift所遇到的坑

作者: jamalping | 来源:发表于2017-10-24 17:59 被阅读0次

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

    • UITableView的左滑删除

    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]
        }
    
    • UITextField的循环监听

    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!)
        }
    

    相关文章

      网友评论

        本文标题:使用RxSwift所遇到的坑

        本文链接:https://www.haomeiwen.com/subject/jpexpxtx.html