④、iOS-RxSwift的Timer、Observable的创建、RxSwiftUI控件(UIDatePicker、UIButton、UISwitch、Slider、Stepper)在实际开发的使用

RxSwift系列
①、RxSwift基础控件的使用、RxSwif-Tableview的使用、RxSwift-SectionTableview结合RxDataSources的使用、RxSwift 网络请求封装的使用
②、RxSwift函数式响应编程思想,RxSwift-KVO、Button、UITextField、ScrollView、手势、通知、定时器、网络请求的使用
③、iOS-RxSwift核心逻辑,RxSwift实战案例,Observable的继承链,Observable订阅的流程、OnNext的流程、AnonymousObservableSink业务逻辑用
④、RxSwift的Timer、Observable的创建、RxSwiftUI控件(UIDatePicker、UIButton、UISwitch、UISlider、UIStepper)在实际开发的使用

推荐网站
RxSwift官方文档
RxSwift-Github源码
RxSwift的操作符

Demo
Demo-①、RxSwift基础控件的使用、RxSwif-Tableview的使用、RxSwift-SectionTableview结合RxDataSources的使用、RxSwift 网络请求封装的使用
Demo-②、RxSwift函数式响应编程思想,RxSwift-KVO、Button、UITextField、ScrollView、手势、通知、定时器、网络请求的使用-1
Demo-②、RxSwift函数式响应编程思想,RxSwift-KVO、Button、UITextField、ScrollView、手势、通知、定时器、网络请求的使用-2-Observable

请添加图片描述

①、RxSwift的Timer为什么不受RunLoop影响、系统的Timer有哪些受影响

0.如何鉴别Timer是否受RunLoop的影响

在页面添加一个TextView
开启定时器 
看定时是否还在走动。
如果在走动 说明不受影响

1、Timer - RunLoop.common不受影响、.default就受影响

从下面的代码看出 TImer加到RunLoop的Common里面去。不受印象
所以联想到 RxSwift timer - 猜测Timer -> .common

  func code_timer(){
//            timer = Timer.init(timeInterval: 1, target: self, selector: #selector(timerFire), userInfo: nil, repeats: true)
//        RunLoop.current.add(timer, forMode: .default) // 受影响
//        RunLoop.current.add(timer, forMode: .common) // 不受影响

        // 受影响
            timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { (timer) in
                print("timer \(timer)")
            })

    }
        @objc func timerFire(){
        print("yh")
    }

2、CGD(定时器推荐使用,更精准)

    func code_gcdTimer(){
        // gcd 不受RunLoop影响
        gcdTimer = DispatchSource.makeTimerSource()
        gcdTimer?.schedule(deadline: DispatchTime.now(),repeating: DispatchTimeInterval.seconds(1)) // 开始
        // 处理事务
        gcdTimer?.setEventHandler(handler: {
            print("code_gcdTimer hello GCD")
        })
        // 默认是挂起状态
        // 重新开始、
        gcdTimer?.resume()
        // 内存管理问题 先要cancel 才能致空
//        gcdTimer?.suspend()
//        gcdTimer?.cancel()
//        gcdTimer = nil
    }

3、CADisplayLink - RunLoop.common不受影响

  func code_CADisplayLink(){
        // 受影响
        cadTimer = CADisplayLink(target: self, selector: #selector(timerFire))
        cadTimer?.preferredFramesPerSecond = 1 // 每秒帧数
        cadTimer?.add(to: RunLoop.current, forMode: .default)
    }

⭐️4、RxSwift的Timer是封装的GCD

我们先定义一个RxSwift的Timer Observable<Int>.timer(RxTimeInterval.seconds(1), period: RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)
我们查看该函数的内部 继续进入return Timer( dueTime: dueTime, period: period, scheduler: scheduler )函数
找到Timer的run函数.查看TimerSink的类 找到run函数 继续进去return self.parent.scheduler.schedulePeriodic(0 as Observer.Element, startAfter: self.parent.dueTime, period: self.parent.period!) { state in self.lock.performLocked { self.forwardOn(.next(state)) return state &+ 1 } }
找到ConcurrentDispatchQueueSchedulerschedulePeriodic,继续跟踪进去
找到DispatchQueueConfigurationschedulePeriodic

        Observable<Int>.timer(RxTimeInterval.seconds(1), period: RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)

>  最终定位到 DispatchQueueConfiguration的schedulePeriodic	
看到代码
        let timer = DispatchSource.makeTimerSource(queue: self.queue)
        timer.schedule(deadline: initial, repeating: period, leeway: self.leeway)
就是用GCD封装的
            timerState = action(timerState)
我们希望timerState 是一个函数

我们回看代码 Timer的Run有一个尾随闭包
  func run() -> Disposable {
        return self.parent.scheduler.schedulePeriodic(0 as Observer.Element, startAfter: self.parent.dueTime, period: self.parent.period!) { state in
            self.lock.performLocked {
                self.forwardOn(.next(state))
                return state &+ 1
            }
        }
    }

//尾随闭包
{ state in
            self.lock.performLocked {
                self.forwardOn(.next(state))
                return state &+ 1
            }
forwardOn跟进去 最终会走 observer.on
        self.observer.on(event)

1.Rxswift的Timer如何销毁
    var timerDisposeBag = DisposeBag()
    var RxTimer: Observable<Int>!

  func Observable_Timer(){
//        timer =  Observable<Int>.timer(RxTimeInterval.seconds(1), period: RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)
        var a = 0
        RxTimer = Observable<Int>.interval(RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)
        RxTimer.subscribe(onNext:{(num) in
            a += 1
            if a > 5 {
            }
            print(num)
        }).disposed(by: timerDisposeBag)
        
        // timer 序列 不发生 完成 & 错误 & 销毁
        
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("来了")
        // 销毁RxSwift定时器1
        timerDisposeBag = DisposeBag()

    }


②、RxSwift-Observable的创建

1.Observableempty

  //MARK:observable 创建
    // 空序列 - 本来序列的事件是Int类型,这里调用了empty函数 没有序列 。只能complete
    func eobservable_empty(){
        let emptyOb = Observable<Int>.empty()
        _ = emptyOb.subscribe(onNext: {(number) in
            print("eobservable_empty 订阅 :",number)
        },onError: { (error) in
            print("eobservable_empty error :",error)
        }, onCompleted: {
            print("eobservable_empty 完成")
        },onDisposed: {
            print("eobservable_empty 销毁 释放")
        })

    }

2.Observablejust

func observable_just(){
        // 数组
        let array = ["yy","yh"]
        Observable<[String]>.just(array)
            .subscribe({(event) in
                print(event)
            })
            .disposed(by: disposeBag)
    }

3.Observableof

  func observable_of(){
        // 字典
        let dict :[String : Any] = ["name":"yy","age":18]
        Observable<[String: Any]>.of(dict)
            .subscribe({(event) in
                print(event)
            })
            .disposed(by: disposeBag)
    }

4.Observablefrom

    func eobservable_from(){
        // MARK :from
        // 从集合中获取序列 : 数组、结合、set - 获取序列 - 有可选项处理 -更安全
        Observable<[String]>.from(optional: ["yy","yh"])
            .subscribe({(event) in
                print(event)
            })
            .disposed(by: disposeBag)
    }

5.Observabledefer

func observable_defer(){
        // MARK :defer
        // 这里有一个需求 :  动态序列 - 根据外界的标识 - 动态输出
        
        //  使用deferred
        // ()方法延迟 Observable 序列的初始化 通过传入的block来实现Observable序列的初始化并且返回。
        
        var isodd = true
        _ = Observable<Int>.deferred{() -> Observable<Int> in
            // 这里设置我们的序列 -- 登录模块  username password 登录 注册
            isodd = !isodd
            if isodd {
                return Observable.of(1,3,5,7,9)
            }
            return Observable.of(2,4,6,8)
        }.subscribe{ (event) in
            print(event)
        }
    }

6.Observablegenerate

    func observable_genrate(){
        // MARK :genrate
        // 该方法创建一个只有当提供的所有判断条件都为 true的时候 。才会给出 Observable 序列
        // 初始值给定 然后判断条件1 在判断条件2 会一直递归下去。直到条件1或 跳转2 不满足
        //  类似 数组遍历循环
        Observable.generate(initialState: 0,
                            condition: {$0 < 10},
                            iterate: {$0 + 2})
            .subscribe({(event) in
                print("eobservable_genrate ",event)
            })
            .disposed(by: disposeBag)
    }

7.Observabletimer

7.1 timer
    func observable_timer(){
        // MARK: timer
        // 第一个参数 : 第一次响应距离现在的时间
        // 第二个参数 : 时间间隔
        // 第三个参数 :  线程
        
        Observable<Int>.timer(RxTimeInterval.seconds(5), period: RxTimeInterval.seconds(2), scheduler: MainScheduler.instance)
            .subscribe{ (event) in
                print("observable_timer ",event);
            }
            .disposed(by: disposeBag)
        
        
        // timer2
        // 因为没有指定期限 period 。故认定为一次性
        Observable<Int>.timer(RxTimeInterval.seconds(1),scheduler: MainScheduler.instance)
            .subscribe{(event) in
                print("因为没有指定期限 period 。故认定为一次性 ",event)
            }
    }

7.2 interval
    func observable_interval(){
        // MARK: timer - interval
        // 定时器
        Observable<Int>.interval(RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)
            .subscribe{(event) in
                print("observable_interval ",event)
            }
    }

8.ObservablerepeatElement

    func observable_repeatElement(){
        // MARK: repeatElement
        // 该方法创建一个可以无限发出给定元素的event的 Observable 序列(永不终止)
        Observable<Int>.repeatElement(5)
            .subscribe{(event) in
                print("observable_repeatElement ",event)
            }
    }

9.Observableerror

    func observable_error(){
        // MARK: error
        // 该方法创建一个可以无线发出给定元素的event的 Observable 序列(永不终止)
        Observable<Int>.error(NSError.init(domain: "yyerror", code: 10086, userInfo: ["reason":"unkonw"]))
            .subscribe{(event) in
                print("observable_error ",event)
            }
    }

10.Observablenever

    func observable_never(){
        // MARK: never
        // 该方法创建一个永远不会发出 event(也不会终止的)的 Observable序列
        // 这种类型的响应源 在测试 或者在组合操作符中 禁用确切的源非常有用
        Observable<Int>.never()
            .subscribe{(event) in
                print("observable_never ",event)
            }
    }

③、RxSwift-UI控件的使用 - 以实际开发控件为例

1.import RxSwift 和 import RxCocoa 说明

import RxSwift // 提供rx的思维
import RxCocoa // 建立RxSwift和UIKit的关系

2.RxSwift-UI控件 UIDatePicker的使用

YHDataPickerValidator

class YHDataPickerValidator: NSObject {

    // 选择的日期是否小于当天;
    class func isValidDate(date: Date) -> Bool{
        let calendar = NSCalendar.current
        let compare  = calendar.compare(date,
                                        to: Date.init(),
                                        toGranularity: .day)
        return compare == .orderedAscending
    }

}

    func RxSwift_UIDatePicker(){
        self.birthdayPicker.layer.borderWidth = 1;
        // 首先我们的出生日期不能早于今天。否则边框变色
        let birthdayOB = birthdayPicker.rx.date.map{
            YHDataPickerValidator.isValidDate(date: $0) // 返回的是yes 还是no
        }
        // map 相当于 birthdayOB 是原来的ob 。经过 map 之后变成 另外一个ob
        
        // map 相当于 映射
        // f(x) x = 1 f(x)
        // x = x + 2 = 3
        // 背景色
        birthdayOB.map{
            $0 ? UIColor.orange : UIColor.red // 返回一个color 然后再订阅
        }
        .subscribe(onNext:{ (color) in
            print(birthdayOB)
            self.birthdayPicker.layer.borderColor = color.cgColor
        })
        .disposed(by: disposeBag)

    }

3.RxSwift-UI控件 UIButton的使用 以选择性别、更新按钮控制为例子

    @IBOutlet weak var maleBtn: UIButton!
    @IBOutlet weak var femaleBtn: UIButton!
       func RxSwift_Btn(birthdayOB:Observable<Bool>){
        // 接下来我们处理性别选择
        // 现在我们想 性别选择按钮的背后的逻辑
        // 1. 性别的选择 和 上面生日的选择 决定下面更新按钮 : 我们常见的必选项
        // 2 . 性别的选择 是由我们的两个按钮的处理。我们没必要分开逻辑
        let genderSelectOB = BehaviorRelay<YHGender>(value: .notSelcted)
        maleBtn.rx.tap
            .map{ YHGender.male} // 男生的序列
            .bind(to: genderSelectOB) // 绑定到我们定义的序列
            .disposed(by: disposeBag)

        femaleBtn.rx.tap
            .map{ YHGender.female} // 女生的序列
            .bind(to: genderSelectOB) // 绑定到我们定义的序列
            .disposed(by: disposeBag)

        
        genderSelectOB.asObservable().subscribe(onNext:{(gender) in print(gender)
            switch gender{
            case .male:
                self.maleBtn.setImage(UIImage(named: "check"), for: .normal)
                self.femaleBtn.setImage(UIImage(named: "uncheck"), for: .normal)
            case .female:
                self.femaleBtn.setImage(UIImage(named: "check"), for: .normal)
                self.maleBtn.setImage(UIImage(named: "uncheck"), for: .normal)
            default:
                break;

            }
            
        })
            .disposed(by: disposeBag)
        
// 最终的按钮是否能够点击 控制
        let genderSELOB = genderSelectOB.asObservable()
            .map{$0 != .notSelcted ? true : false}
        
        // 控制我们的点击更新按钮 - 被两个序列共同影响
        Observable.combineLatest(birthdayOB,genderSELOB) {$0 && $1}
        .bind(to: updateBtn.rx.isEnabled)
        .disposed(by: disposeBag)
        
    }


4.RxSwift-UI控件 UISwitch UISlider的使用 以Switch开关、UISlider拖动相互关联为例子

    @IBOutlet weak var knowSwiftSwitch: UISwitch!
    @IBOutlet weak var swiftLevelSlider: UISlider!
  func RxSwift_UISwitch(){
        // 接下来 我们来玩玩其他控件
        /**
         对于UISwitch来说:
         
         当UISwitch为OFF时,表示用户不了解Swift,因此,下面的UISlider应该为0;
         当UISwitch为ON时,可以默认把UISlider设置在1/4的位置,表示大致了解;
         
         对于UISlider来说:
         
         当UISlider不为0时,应该自动把UISwitch设置为ON;
         当UISlider为0时,应该自动把UISwitch设置为OFF;
         */
        
        // on off -> 0.25 0
        knowSwiftSwitch.rx.value.map{$0 ? 0.25 : 0}
            .bind(to: swiftLevelSlider.rx.value)
            .disposed(by: disposeBag)
        
        
        // 0 1 true flase
        swiftLevelSlider.rx.value.map{$0 != 0 ? true : false}
            .bind(to: knowSwiftSwitch.rx.isOn)
            .disposed(by: disposeBag)
    }

5.RxSwift-UI控件 UIStepper的使用 以UIStepper增加减少关联图片变大变小为例子

    @IBOutlet weak var passionToLearnStepper: UIStepper!
    @IBOutlet weak var heartHeightConstraint: NSLayoutConstraint! // 图片的约束
        func RxSwift_Stepper(){
        passionToLearnStepper.rx.value.skip(1)
            .subscribe(onNext:{ (value) in
                // 关联爱心按钮变大变小
                self.heartHeightConstraint.constant = CGFloat(value - 10)
            })
            .disposed(by: disposeBag)
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇夜iOS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值