美文网首页
RxSwift 简单使用和与swift的写法对比

RxSwift 简单使用和与swift的写法对比

作者: 紫水依 | 来源:发表于2019-07-27 00:07 被阅读0次

    RxSwift特点

    swift是一门静态语言,不像OC那样可以动态的传输数据发送消息,RxSwift可以弥补swift的这种语言特性。
    RxSwift函数响应式编程思想,其代码可读性强、复用性高、容易理解、很稳定,抽象了异步编程统一代码风格。

    函数响应式编程FRP(Function Reactive Programming)

    1、函数式是以函数作为参数的编程方式

    函数式例子:

            //获取大于3的数字之后将其加1,并取结果中的偶数
    
            let array = [1, 2, 3, 4, 5, 6, 7]
            for num in array {
                if (num > 3) {
                    let number = num + 1
                    if (number % 2 == 0) {
                        print(number)
                    }
                }
            }
    
            //函数式写法:filter函数参数是一个闭包,$0 > 3表示取数组第一个值大于3
            array.filter { $0 > 3 }
                .filter { ($0 + 1) % 2 == 0 }
                .forEach { print($0) }
    

    对比之后发现函数式可读性和可操作性更强

    2、响应式:RxSwift 简单使用
    KVO

    KVO是runtime的运行时机制,在静态语言swift里无法执行,需要加上@objc dynamic才能执行,@objc的意思是使用OC访问这段代码,dynamic是开启运行时功能

    swift写法:

    //  LYPerson.swift
    class LYPerson: NSObject {
        @objc dynamic var name:String = "ly"
    }
    
    //  ViewController.swift
        override func viewDidLoad() {
            super.viewDidLoad()
            self.setupKVO()
        }
        func setupKVO() {
            self.person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
        }
        
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            person.name = "\(person.name) + "
        }
        
        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
            print(change as Any)
        }
        
        deinit {
            self.person.removeObserver(self, forKeyPath: "name", context: nil)
        }
    
    /*
    输出结果:
    Optional([__C.NSKeyValueChangeKey(_rawValue: new): ly + , __C.NSKeyValueChangeKey(_rawValue: kind): 1])
    Optional([__C.NSKeyValueChangeKey(_rawValue: new): ly +  + , __C.NSKeyValueChangeKey(_rawValue: kind): 1])
    */
    

    RxSwift写法:

    //  ViewController.swift
        func setupKVO() {
            self.person.rx.observeWeakly(String.self, "name")
                .subscribe(onNext: { (value) in
                    print(value as Any)
                })
                .disposed(by: disposeBag)
        }
    
    /*
    输出结果:
    Optional("ly")
    Optional("ly + ")
    Optional("ly +  + ")
    */
    
    Button

    swift写法:

    func setupButton() {
            self.button.addTarget(self, action: #selector(buttonClick), for: .touchUpInside)
        }
    @objc func buttonClick() {
            print("点击了按钮")
        }
    

    RxSwift写法:

    //业务逻辑和功能逻辑在一起
    func setupButton() {
            self.button.rx.tap
                .subscribe(onNext: { () in
                   print("点击事件")
                })
                .disposed(by: disposeBag)
    
            self.button.rx.controlEvent(.touchUpInside)
                .subscribe(onNext: { () in
                    print("点击事件1")
                })
                .disposed(by: disposeBag)
        }
    
    • rx实现:
    //协议拓展
    extension ReactiveCompatible {
    
        /// Reactive extensions. //提供给外界的属性
        public static var rx: RxSwift.Reactive<Self>.Type
    
        /// Reactive extensions.
        public var rx: RxSwift.Reactive<Self>
    }
    
    /// A type that has reactive extensions. //ReactiveCompatible协议,实现此协议的类都会拥有rx属性
    public protocol ReactiveCompatible {
        /// Extended type
        associatedtype ReactiveBase //关联类型
    
        @available(*, deprecated, message: "Use `ReactiveBase` instead.")
        typealias CompatibleType = ReactiveBase
    
        /// Reactive extensions. //rx的get和set方法,协议属性
        static var rx: Reactive<ReactiveBase>.Type { get set }
    
        /// Reactive extensions. //协议方法
        var rx: Reactive<ReactiveBase> { get set }
    }
    
    /// Extend NSObject with `rx` proxy. //协议实现,NSObject拓展实现协议
    extension NSObject : ReactiveCompatible {
    }
    
    TextField

    swift写法

    class ViewController: UIViewController, UITextFieldDelegate {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            self.setupTextField()
        }
    
        func setupTextField() {
            self.textField.delegate = self
        }
        
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            print(string)
            return true
        }
    }
    /*
    输出结果:
    p
    o
    i
    u
    y
    */
    

    RxSwift写法:

    func setupTextField() {
            self.textField.rx.text.orEmpty
                .subscribe(onNext: { (text) in
                    print(text)
                })
                .disposed(by: disposeBag)
    
    //将textField输入的值绑定到button的title
            self.textField.rx.text
            .bind(to: self.button.rx.title())
        }
    /*
    输出结果:
    p
    po
    poi
    poiu
    poiuy
    */
    
    • bind方法
    /**
         Creates new subscription and sends elements to observer(s).
         In this form, it's equivalent to the `subscribe` method, but it better conveys intent, and enables
         writing more consistent binding code.
         - parameter to: Observers to receives events.
         - returns: Disposable object that can be used to unsubscribe the observers.
         */
        public func bind<Observer>(to observers: Observer...) -> Disposable where Observer : ObserverType, Self.Element == Observer.Element
    
    • title()方法
    /// Reactive wrapper for `setTitle(_:for:)` //Binder将拿到的值赋值给button的title
        public func title(for controlState: UIControl.State = []) -> Binder<String?> {
            return Binder(self.base) { button, title -> Void in
                button.setTitle(title, for: controlState)
            }
        }
    
    ScrollView

    swift写法:

    class ViewController: UIViewController, UIScrollViewDelegate {
        func setupScrollView() {
            self.scrollView.delegate = self
        }
        
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            self.view.backgroundColor = UIColor.init(white: scrollView.contentOffset.y/60, alpha: 1.0)
        }
    }
    

    RxSwift写法:

    func setupScrollView() {
            self.scrollView.rx.contentOffset
                .subscribe(onNext: { [weak self](content) in
                    self?.view.backgroundColor = UIColor.init(white: content.y/60, alpha: 1.0)
                })
                .disposed(by: disposeBag)
        }
    
    gesture手势

    swift写法:

    func setupGesture() {
            let tap = UITapGestureRecognizer()
            self.label.isUserInteractionEnabled = true
            self.label.addGestureRecognizer(tap)
            
            tap.addTarget(self, action: #selector(tapLabel(_ :)))
        }
        
        @objc func tapLabel(_ gesture: UITapGestureRecognizer) {
            print(gesture.view)
        }
    

    RxSwift写法:

    func setupGesture() {
            let tap = UITapGestureRecognizer()
            self.label.isUserInteractionEnabled = true
            self.label.addGestureRecognizer(tap)
            
            tap.rx.event.subscribe(onNext: { (tap) in
                print(tap.view)
            })
            .disposed(by: disposeBag)
        }
    
    NotificationCenter通知,监听键盘避免遮挡输入框

    swift写法:

    func setupNotification() {
            NotificationCenter.default.addObserver(self,
                                                   selector: #selector(keyboardWillShow(_ :)),
                                                   name: UIResponder.keyboardWillShowNotification,
                                                   object: nil)
            NotificationCenter.default.addObserver(self,
                                                   selector: #selector(keyboardWillHide(_ :)),
                                                   name: UIResponder.keyboardWillHideNotification,
                                                   object: nil)
        }
        
        @objc func keyboardWillShow(_ notification: Notification) {
            DispatchQueue.main.async {
                
                let user_info = notification.userInfo
                let keyboardRect = (user_info?[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
                
                let y = keyboardRect.origin.y
                let y2 = (self.textField?.frame.origin.y)! + (self.textField?.frame.size.height)! + 5
                let offset_y = y2 > y ? (y2-y):(0)
                
                UIView.animate(withDuration: 0.25, animations: {
                    self.view.center = CGPoint.init(x: self.view.center.x, y: self.view.center.y - offset_y)
                })
            }
        }
        
        @objc func keyboardWillHide(_ notification: Notification) {
            DispatchQueue.main.async {
                self.view.center = CGPoint.init(x: self.view.center.x, y: self.view.frame.height/2)
            }
        }
        deinit {
            NotificationCenter.default.removeObserver(self)
        }
    

    RxSwift写法:

    func setupNotification() {
            NotificationCenter.default.rx
                .notification(UIResponder.keyboardWillShowNotification)
                .subscribe(onNext: { (noti) in
                    print(noti)
                let user_info = noti.userInfo
                let keyboardRect = (user_info?[UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
                
                let y = keyboardRect.origin.y
                let y2 = (self.textField?.frame.origin.y)! + (self.textField?.frame.size.height)! + 5
                let offset_y = y2 > y ? (y2-y):(0)
                
                UIView.animate(withDuration: 0.25, animations: {
                    self.view.center = CGPoint.init(x: self.view.center.x, y: self.view.center.y - offset_y)
                })
            })
            .disposed(by: disposeBag)
            NotificationCenter.default.rx
                .notification(UIResponder.keyboardWillHideNotification)
                .subscribe(onNext: { (noti) in
                    print(noti)
                    self.view.center = CGPoint.init(x: self.view.center.x, y: self.view.frame.height/2)
                })
            .disposed(by: disposeBag)
        }
    
    timer定时器

    swift写法:(scrollview滚动时定时器会停止计时)

    let timerT = Timer.init(timeInterval: 1, repeats: true) { (kTimer) in
                print(kTimer)
            }
            RunLoop.current.add(timerT, forMode: .default)
            timerT.fire()
    

    RxSwift写法:(scrollview滚动事件不影响定时器计时,实际是根据interval发送响应来执行操作)

    var timer: Observable<Int>!
    
    func setupTimer() {
            timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
            timer.subscribe(onNext: { (num) in
                print(num)
            })
            .disposed(by: disposeBag)
        }
    
    • interval实现
    public static func interval(_ period: RxTimeInterval, scheduler: SchedulerType)
            -> Observable<Element> {
            return Timer(
                dueTime: period,
                period: period,
                scheduler: scheduler
            )
        }
    
    • timer实现,TimerSink()实现定时
    final private class Timer<Element: RxAbstractInteger>: Producer<Element> {
        fileprivate let _scheduler: SchedulerType
        fileprivate let _dueTime: RxTimeInterval
        fileprivate let _period: RxTimeInterval?
    
        init(dueTime: RxTimeInterval, period: RxTimeInterval?, scheduler: SchedulerType) {
            self._scheduler = scheduler
            self._dueTime = dueTime
            self._period = period
        }
    
        override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
            if self._period != nil {
                let sink = TimerSink(parent: self, observer: observer, cancel: cancel)
                let subscription = sink.run()
                return (sink: sink, subscription: subscription)
            }
            else {
                let sink = TimerOneOffSink(parent: self, observer: observer, cancel: cancel)
                let subscription = sink.run()
                return (sink: sink, subscription: subscription)
            }
        }
    }
    
    • TimerSink()实现,通过state的改变达到计时的目的
    final private class TimerSink<Observer: ObserverType> : Sink<Observer> where Observer.Element : RxAbstractInteger  {
        typealias Parent = Timer<Observer.Element>
    
        private let _parent: Parent
        private let _lock = RecursiveLock()
    
        init(parent: Parent, observer: Observer, cancel: Cancelable) {
            self._parent = parent
            super.init(observer: observer, cancel: cancel)
        }
    
        func run() -> Disposable {
            return self._parent._scheduler.schedulePeriodic(0 as Observer.Element, startAfter: self._parent._dueTime, period: self._parent._period!) { state in
                self._lock.lock(); defer { self._lock.unlock() }
                self.forwardOn(.next(state))
                return state &+ 1
            }
        }
    }
    
    network网络请求

    swift写法:

    func setupNetwork() {
        let url = URL(string: "https://www.baidu.com")
            URLSession.shared.dataTask(with: url!) { (data, response, error) in
                print(String.init(data: data!, encoding: .utf8))
            }.resume()
    }
    /*
    输出结果:
    Optional("<html>\r\n<head>\r\n\t<script>\r\n\t\tlocation.replace(location.href.replace(\"https://\",\"http://\"));\r\n\t</script>\r\n</head>\r\n<body>\r\n\t<noscript><meta http-equiv=\"refresh\" content=\"0;url=http://www.baidu.com/\"></noscript>\r\n</body>\r\n</html>")
    */
    

    RxSwift写法:

    let url = URL(string: "https://www.baidu.com")
    func setupNetwork() {
        URLSession.shared.rx.response(request: URLRequest(url: url!))
                .subscribe(onNext: { (response, data) in
                    print(String.init(data: data, encoding: .utf8))
                })
                .disposed(by: disposeBag)
    }
    /*
    输出结果:
    curl -X GET 
    "https://www.baidu.com" -i -v
    Success (1246ms): Status 200
    Optional("<html>\r\n<head>\r\n\t<script>\r\n\t\tlocation.replace(location.href.replace(\"https://\",\"http://\"));\r\n\t</script>\r\n</head>\r\n<body>\r\n\t<noscript><meta http-equiv=\"refresh\" content=\"0;url=http://www.baidu.com/\"></noscript>\r\n</body>\r\n</html>")
    */
    
    • response实现:将request和dataTask放在函数里实现,返回response、data和error信息
    public func response(request: URLRequest) -> Observable<(response: HTTPURLResponse, data: Data)> {
            return Observable.create { observer in
    
                // smart compiler should be able to optimize this out
                let d: Date?
    
                if Logging.URLRequests(request) {
                    d = Date()
                }
                else {
                   d = nil
                }
    
                let task = self.base.dataTask(with: request) { data, response, error in
    
                    if Logging.URLRequests(request) {
                        let interval = Date().timeIntervalSince(d ?? Date())
                        print(convertURLRequestToCurlCommand(request))
                        #if os(Linux)
                            print(convertResponseToString(response, error.flatMap { $0 as NSError }, interval))
                        #else
                            print(convertResponseToString(response, error.map { $0 as NSError }, interval))
                        #endif
                    }
                    
                    guard let response = response, let data = data else {
                        observer.on(.error(error ?? RxCocoaURLError.unknown))
                        return
                    }
    
                    guard let httpResponse = response as? HTTPURLResponse else {
                        observer.on(.error(RxCocoaURLError.nonHTTPResponse(response: response)))
                        return
                    }
    
                    observer.on(.next((httpResponse, data)))
                    observer.on(.completed)
                }
    
                task.resume()
    
                return Disposables.create(with: task.cancel)
            }
        }
    

    参考链接:
    Swift监听键盘通知以及做出一些处理
    55 - Swift 之 Timer (NSTimer )定时器

    相关文章

      网友评论

          本文标题:RxSwift 简单使用和与swift的写法对比

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