RxSwift|RxSwift 入门练习总结

demo.gif 使用的第三方库

target 'WeatherDemo_RxSwift' douse_frameworks!pod 'RxSwift', '~> 3.5.0' pod 'RxCocoa', '~> 3.5.0' pod 'RxDataSources', '~> 1.0.4'end

1.所有的控制器都加上析构函数,以方便查看是否有循环引用
deinit { print("\(self) 释放") }

2.按钮订阅点击事件
tapButton.rx.tap .subscribe({ [unowned self] _ in let numStr : String = self.numberLabel.text! let number = Int(numStr) self.numberLabel.text = String(number! + 1)}).addDisposableTo(disposeBag)

注意: 一定要加[unowned self],或者[weak self]否则会出现循环引用,关于它俩的使用情况,参考@ONEVCAT内存管理,WEAK 和 UNOWNED
3.订阅手势事件,给按钮添加长按手势
let longPressGesture = UILongPressGestureRecognizer() longPressGesture.rx.event .subscribe(onNext: { [unowned self] _ inlet numStr : String = self.numberLabel.text! let number = Int(numStr) self.numberLabel.text = String(number! + 1)}).addDisposableTo(disposeBag) self.tapButton.addGestureRecognizer(longPressGesture)

此处,用了subscribe.onNext.注意:onNext 只监听sequence发出的next事件中的element进行处理,他会忽略error和completed事件
疑问点:大部分情况subscribe 硬敲出来的 为啥代码没有自动补全??? 4.结合tableView,Variable使用示例
// Variable流,初始值字符串数组 let items = Variable(["Mike", "Apples", "Ham", "Eggs"])let items2 = [ "Fish", "Carrots", "Mike", "Apples", "Ham", "Eggs", "Bread", "Chiken", "Water" ]// Variable使用必须要加asObservable // 数据流绑定到tableView items.asObservable() .bind(to: tableView.rx.items(cellIdentifier: "Cell",cellType:UITableViewCell.self),curriedArgument: { (row, element, cell) in cell.textLabel?.text = element }).addDisposableTo(disposeBag)// 原生的refresh refreshControl.rx.controlEvent(.valueChanged) .subscribe(onNext: { [unowned self] _ in // 更改Variable.value 模拟刷新 items.value = https://www.it610.com/article/items2 self.refreshControl.endRefreshing() }).addDisposableTo(disposeBag)tableView.addSubview(refreshControl)

知识点:
  • 要理解Variable,需要先理解Subject,Subjet是observable和Observer之间的桥梁,一个Subject既是一个Obserable也是一个Observer,他既可以发出事件,也可以监听事件
  • BehaviorSubject : 当你订阅了BehaviorSubject,你会接受到订阅之前的最后一个事件
  • Variable是BehaviorSubject一个包装箱,就像是一个箱子一样,使用的时候需要调用asObservable()拆箱,里面的value是一个BehaviorSubject,他不会发出error事件,但是会自动发出completed事件
5.逆向传值,代理使用示例
// 代理声明 必须要继承 class 否则报错 protocol DataEnteredDelegate: class { func userDidEnterInformation( info: String ) }// 代理声明必须要weak,防止循环引用 weak var delegate : DataEnteredDelegate? = nil// 监听键盘右下角done事件,调用代理方法 @IBAction func textOnExit(_ sender: Any) { delegate?.userDidEnterInformation(info: textField.text!) self.navigationController?.popViewController(animated: true) }

知识点:
  • 需要把protocol 限制在 class 内,这是因为 Swift 的 protocol 是可以被除了 class 以外的其他类型遵守的, 而对于像 struct 或是 enum 这样的类型,本身就不通过引用计数来管理内存,所以也不可能用 weak 这样的 ARC 的概念来进行修饰
    王巍 (@ONEVCAT) delegate
6. 第三方RxDataSources使用示例
// 1.数据流 just用法 let items = Observable.just([ SectionModel(model: "B",items:[ "Barbara Cole", "Barbara Cooper", "Barbara Diaz", "Barbara Edwards", "Barbara Garcia", "Barbara Gray", "Barbara Griffin", "Barbara Hill", "Barbara Howard", "Barbara Hughes" ]), SectionModel(model:"C",items:[ "Carol Lopez", "Carol Lopez" ]), SectionModel(model: "E", items: [ "Elizabeth Jenkins", "Elizabeth Kelly" ]), SectionModel(model: "H", items: ["Helen Anderson", "Helen Bailey", "Helen Cole", "Helen Cox"]), SectionModel(model: "J", items: ["James Anderson", "James Barnes", "James Bell"]), SectionModel(model: "K", items: ["Karen Green", "Karen Jenkins", "Karen Jones", "Karen Jordan"]), SectionModel(model: "L", items: ["Linda Taylor", "Linda Taylor", "Linda Torres", "Linda West", "Lisa Brooks"]), SectionModel(model: "M", items: ["Margaret Bell", "Margaret Coleman", "Margaret Cox", "Margaret Foster"]), SectionModel(model: "R", items: ["Robert Clark", "Robert Coleman", "Robert Cook", "Robert Cook"]), SectionModel(model: "S", items: ["Susan Fisher", "Susan Ford", "Susan Ford", "Susan Hernandez", "Susan Howard"]), ])// 2.创建数据源 类型 let dataSource = RxTableViewSectionedReloadDataSource>()// 3. dataSources配置cell fileprivate func setupDataSource() {// 参数必须4个,_占位用 dataSource.configureCell ={ (_,tableView,IndexPath,element) in let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")! cell.textLabel?.text = element return cell }// 监听右侧边缘小字母点击事件 dataSource.sectionForSectionIndexTitle = { (dataSource,title,index) -> Int in print("\(index)") return index }dataSource.sectionIndexTitles = { data -> [String]? in return data.sectionModels.map{ $0.model } } }//4. 数据流items,绑定到dataSource上 items.bind(to: tableView.rx.items(dataSource: dataSource))// 5. 设置tableView代理 _ = tableView.rx.setDelegate(self)

7. 自定义可观察序列create 示例
//create 自定义可观察序列 返回的WeatherData 类型流 func fetchWeatherData() -> Observable { let observable = Observable.create { [weak self] observer in if let weakSelf = self{ let time = 0.5 + TimeInterval(arc4random_uniform(10)) / 10.0// 主线程延迟处理,模拟网络请求数据 DispatchQueue.main.asyncAfter(deadline: .now() + time, execute: { let shouldFail = arc4random_uniform(2) == 0 if shouldFail { observer.onError(NSError(domain:"Fake network error", code: 0, userInfo: nil)) }else{ observer.onNext(weakSelf.createRandomWeatherData()) observer.onCompleted() }}) } return Disposables.create() // 固定写法,记住 需实现.onError() .onNext .onCompleted } return observable.shareReplay(1) }

// 建议使用addDisposableTo self.viewModel.locationName.drive(self.locationLabel.rx.text).addDisposableTo(disposeBag)// 而不是用 disposed(by: disposeBag) self.viewModel.locationName.drive(self.locationLabel.rx.text).disposed(by: disposeBag)// 按钮tap事件建议使用subscribe button.rx.tap .subscribe(onNext:{ [unowned self] in let selectedDate = dateFormatter.string(from: self.datePicker.date) self.title = selectedDate }).addDisposableTo(disposeBag)// 而不是用bind button.rx.tap .bind { [unowned self] in let selectedDate = dateFormatter.string(from: self.datePicker.date) self.title = selectedDate }.addDisposableTo(disposeBag)

【RxSwift|RxSwift 入门练习总结】RxSwift概念理解
RxSwift学习资料,内涵很多RxSwift开源项目
本示例下载

    推荐阅读