RxSwift 入坑好多天 - 终于有了一点理解

时间:2022-08-30 22:10:22

一、前言

  • 江湖上都在说现在就要赶紧学 swift 了,即将是 swift 的天下了。在 api 变化不大的情况下,swift 作为一门新的语言,集众家之所长,普通编码确实比 oc 要好用的多了
  • 老早就听说 MVVM 的概念及响应式函数式编程,微软确实厉害。自己最近没什么事,就前来入坑了

二、学习方式

三、自己写注册登录及 tableView 的一点理解

  • 关于观察者被观察者(Observable)发出序列

    • UI 控件在 RxCocoa 下某些属性都是被观察者(Observable),都可以发出序列,常见的有
      • 控件的 text 类型是 ControlProperty<String> ,最终遵循 ObservableType协议
      • 按钮的点击 tap 类型是 ControlEvent<Void>,最终遵循 ObservableType协议
    • 对于设置 UI 控件的一些 Bool 类型的属性,如可输入,可点击,一般用 UIBindingObserver<UIElementType, Value>(遵循 ObserverType协议) 来生成观察者,对接受的数据条件进行判断是否可以输入、可点击
    // MARK: RX 扩展 计算型属性
    // textfield 根据展示验证后的结果能否输入,验证过了才能输入
    extension Reactive where Base: UITextField { var inputEnable: UIBindingObserver<Base, ValidationResult> {
    return UIBindingObserver(UIElement: base, binding: {
    (textField, result) in textField.isEnabled = result.isValid
    })
    }
    }
    • 关于在 VM 中常用的 Subject
      • Variable、PublishSubject 是 Subject 的一种,可当观察者被 bindTo,可当序列数据源 Observable
        • Variable 它不会因为错误终止也不会正常终止, 适合做数据源,可以用于控件的 text 属性
        • PublishSubject 与普通的Subject不同,在订阅时并不立即触发订阅事件,而是允许我们在任意时刻手动调用onNext(),onError(),onCompleted来触发事件,可以用于按钮的点击
    • 关于被观察者(Observable)的一些常用的 api
      • map 不会产生新的序列
      • flatMapLatest 会产生新的序列
      • combineLatest 不会产生新的序列
  • 关于 MVVM 文件夹分类

    • 之前 MVC 的与 iOS 里的 Controller、View 一一对应,很好理解,而 MVVM 里 Controller 属于 V 了,负责处理控制器跳转和将 View 和 VM 绑定等,大部分的业务逻辑代码都在 VM 里,感觉应该是这样

      RxSwift 入坑好多天 - 终于有了一点理解

    • 自始至终感觉 iOS 里的 model 这一层很轻,有时仅仅是建立了模型类而已。感觉应该是各种数据操作如数据库查询等都应该是 model 这一层的

  • 关于** 双向绑定 **

    • 首先要有一些控件,理清楚需要监听这些控件的哪些属性值
    • 然后 VM 里建立好这些属性值对应的 Subject
    • 一般控制器里生成 VM 对象,将控件的 Observable 的属性绑定到 VM 的 Subject 属性上,这样可在 VM 里监听到控件属性值的改变,此时 Subject 是 Observer,完成一次绑定
    • 在 VM 内,将 Subject 变成 Observable,生成对应 VM 可被观察者属性(用属性保存加工变换后的 Observable )。这里 Subject 是 Observable,可通过 map 、filter 等各种操作,操作的数据就是 Subject 观察到的序列,相应模块的整个业务逻辑都在此处。
    • 在控制器里,再将 VM 的可被观察者属性绑定到 UI 控件上,在此完成双向绑定
    override func viewDidLoad() {
    super.viewDidLoad()
    let regiestViewModel = RegiestViewModel()
    // 这里做绑定: UI控件 --> VM VM -> UI控件
    // 1.UI控件 --> VM
    nameTextField.rx.text.orEmpty
    .bindTo(regiestViewModel.username)
    .addDisposableTo(disposeBag)
    pwdTextField.rx.text.orEmpty
    .bindTo(regiestViewModel.userPwd)
    .addDisposableTo(disposeBag)
    repeatPwdTextField.rx.text.orEmpty
    .bindTo(regiestViewModel.repeatPwd)
    .addDisposableTo(disposeBag)
    regiestBtn.rx.tap
    .bindTo(regiestViewModel.registerTaps)
    .addDisposableTo(disposeBag)
    // 2.VM -> UI控件
    // 显示结果的 label 上
    regiestViewModel.usernameValid
    .bindTo(nameTipLabel.rx.validResult)
    .addDisposableTo(disposeBag)
    // 绑定 密码框是否可以输入
    regiestViewModel.usernameValid
    .bindTo(pwdTextField.rx.inputEnable)
    .addDisposableTo(disposeBag)
    regiestViewModel.passwordValid
    .bindTo(pwdTipLabel.rx.validResult)
    .addDisposableTo(disposeBag)
    regiestViewModel.passwordValid
    .bindTo(repeatPwdTextField.rx.inputEnable)
    .addDisposableTo(disposeBag)
    regiestViewModel.repeatPwdValid
    .bindTo(repeatPwdTipLabel.rx.validResult)
    .addDisposableTo(disposeBag)
    // 按钮不是绑定, 按钮是 subcribe, 需要操作的
    regiestViewModel.registerButtonEnabled
    .subscribe (onNext: { [weak self] (result) in
    self?.regiestBtn.isEnabled = result
    self?.regiestBtn.alpha = result ? 1 : 0.8
    })
    .addDisposableTo(disposeBag)
    // 注册结果 : 注册成果或失败 要展示在 UI 上
    regiestViewModel.registeResult
    .subscribe(onNext:{ [weak self] result in
    switch result {
    case let .failed(message):
    self?.showAlter(message: message)
    case let .ok(message):
    self?.showAlter(message: message)
    case .empty:
    self?.showAlter(message: "")
    }
    })
    .addDisposableTo(disposeBag)
    // 跳转到登录界面按钮的点击
    loginVcBtn.rx.tap
    .subscribe(onNext: {
    let loginVc = LoginViewController()
    loginVc.title = "请登录"
    self.navigationController?.pushViewController(loginVc, animated: true)
    })
    .addDisposableTo(disposeBag)
    }
  • 关于 tableView

    • 这里需要 RxDataSources 这个配套的框架

    • 控制器里需要一个 dataSource

      let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, HerosItem>>()
    • 控制器里用这个 dataSource 配置 cell

      dataSource.configureCell = { (_, tableView, indexPath, item) in
      var cell = tableView.dequeueReusableCell(withIdentifier: "herosCell")
      if cell == nil {
      cell = UITableViewCell(style: .subtitle, reuseIdentifier: "herosCell")
      }
      cell!.imageView?.image = UIImage(named: item.icon)
      cell!.textLabel?.text = item.name
      cell!.detailTextLabel?.text = item.intro
      return cell!
      }
    • 用 VM 创建出数据 Observable,发出序列,绑定到dataSource 上,完成数据的绑定

      homeViewMode.getSearchResult()
      .bindTo(tableView.rx.items(dataSource: dataSource))
      .addDisposableTo(disposeBag)
    • 其他操作

      • tableView 的代理
        tableView.rx
        .setDelegate(self)
        .addDisposableTo(disposeBag)
      • tableView cell 的点击
        tableView.rx.itemSelected
        .map { [weak self] indexPath in
        return (indexPath, self?.dataSource[indexPath])
        }
        .subscribe(onNext: {(indexPath, item) in
        self.showAlter(item: item)
        })
        .addDisposableTo(disposeBag)
    • 感觉像一个固定的代码模式,将数据源的代码都移到 VM 里了

    • 另外如果做实时搜索的话,用双向绑定效果那是极好的,将搜索框的搜索关键字绑定到 VM 里,在用 VM 产生序列绑定到 tableView 上

四、本例 demo 地址

五、其他

  • MVVM 的使用并没有那么普及,大多数还是 MVC,关于 MVC 的理解和减少控制器的代码量和维护难度是一个难题,有篇文章可参考 http://www.infoq.com/cn/articles/rethinking-mvc-mvvm
  • 对于 RxSwift,像 swift 里的可选类型的处理及 swift 里的多种闭包类型及简写,理解还急需提高;对 RxSwift 的 api 还要继续熟悉,以及后面的多线程及整个项目都用 MVVM 部署还需要更多的实践

RxSwift 入坑好多天 - 终于有了一点理解的更多相关文章

  1. oracle入坑日记&lt&semi;三&gt&semi;用户详解&lpar;角色理解&rpar;

    1   用户是什么 1.1.权限管理是Oracle的精华,不同用户登录到同一数据库中,可能看到不同数量的表,拥有不同的权限.Oracle 的权限分为系统权限和数据对象权限,共一百多种.如果把Oracl ...

  2. 大神都在看的RxSwift 的完全入坑手册

    大神都在看的RxSwift 的完全入坑手册 2015-09-24 18:25 CallMeWhy callmewhy 字号:T | T 我主要是通过项目里的 Rx.playground 进行学习和了解 ...

  3. 【Xbox one S】开箱&amp&semi;开机&amp&semi;初入坑心得

    再来一发水贴,先上产品标准照镇贴: 前言 身为一个资深单机游戏玩家,常年混迹在PC平台,但内心深处一直对主机有种迷之向往,感觉那才是单机游戏的正处之地,坐沙发上拿着手柄对着电视跌宕起伏才是正确的游戏姿 ...

  4. 入坑IT十年(二)技术以外

    上一篇博客里提到:技术越来越简单,发布后不久,就看到<技术并不是越来越简单>,这显然是打擂台来了. 技术究竟是不是越来越简单?其实这个问题,要看你究竟是以什么角度来思考这个问题.我们可以举 ...

  5. Linux探索之路1---CentOS入坑笔记整理

    前言 上次跟运维去行方安装行内环境,发现linux命令还是不是很熟练.特别是用户权限分配以及vi下的快捷操作.于是决定在本地安装一个CentOS虚拟机,后面有时间就每天学习一点Linux常用命令. 作 ...

  6. 1-STM32带你入坑系列&lpar;STM32介绍&rpar;

    由于自己的物联网开发板上的单片机是用的STM32,但是有些朋友没有用过,所以我将用这块开发板,带着大家入门STM32 先介绍一下STM32,我是在大三下学期的时候开始接触STM32,当时是想做一个小车 ...

  7. c&num;调用c&plus;&plus; dll 入坑记录

    1.DLL引用坑 [DllImport("NetDLL.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConve ...

  8. web前端入坑第二篇:web前端到底怎么学?干货资料! 【转】

    http://blog.csdn.net/xllily_11/article/details/52145172 版权声明:本文为博主[小北]原创文章,如要转载请评论回复.个人前端公众号:前端你别闹,J ...

  9. Linux运维一定要知道的六类好习惯和23个教训,避免入坑!

    Linux运维一定要知道的六类好习惯和23个教训,避免入坑! 从事运维三年半,遇到过各式各样的问题,数据丢失,网站挂马,误删数据库文件,黑客攻击等各类问题. 今天简单整理一下,分享给各位小伙伴. 一. ...

随机推荐

  1. Task示例,多线程

    class Program { static void Main(string[] args) { Run(); } public static async void Run() { var task ...

  2. Samba实现Linux与Window文件的传输

    Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通 ...

  3. Qt之Meta-Object系统

    简述 Qt的元对象系统(Meta-Object System)提供了信号与槽机制,可用于对象间通信.运行时类别信息和动态属性系统. 元对象系统基于三个方面: QObject类:为objects提供了一 ...

  4. iOS警告-Warning&colon; Error creating LLDB target at path(模拟器警告)

    Warning: Error creating LLDB target at path '/Users/apple/Library/Developer/Xcode/DerivedData/Observ ...

  5. OD使用经验【转载】

    文章整理发布:黑客风云  1.我的os是winXP,无法使用trw2000,而softice装了多次均未成功,还蓝屏死机多次.郁闷. 2.友好的gui界面,不像softice.可以边干活边听歌,不像s ...

  6. (转载)delphi 常用函数&lpar;数学&rpar;

    delphi 常用函数(数学) Delphi中怎么将实数取整? floor 和 ceil 是 math unit 里的函数,使用前要先 Uses Math.trunc 和 round 是 system ...

  7. 在vs2013上的编译tesseract-ocr

    在vs2013上的编译tesseract-ocr OCR(Optical Character Recognition):光学字符识别,是指对图片文件中的文字进行分析识别,获取的过程. Tesserac ...

  8. Scrapy爬取Ajax(异步加载)网页实例——简书付费连载

    这两天学习了Scrapy爬虫框架的基本使用,练习的例子爬取的都是传统的直接加载完网页的内容,就想试试爬取用Ajax技术加载的网页. 这里以简书里的优选连载网页为例分享一下我的爬取过程. 网址为: ht ...

  9. css学习&lowbar;css布局案例

    1.中间栏先加载  !!!(若不是这个条件的话  ,那可以用  calc 或者flex布局来实现  中间栏自适应,左右栏定宽) 2.中间栏自适应   width:100% 3.左右栏固定宽 左中右  ...

  10. angular-repeat

    ng-repeat="name in 变量名字 track by $index" 一个数组的时候ng-repeat="name in 变量名字" {{x.nam ...