美文网首页
ReactiveCocoa(RAC)响应式编程

ReactiveCocoa(RAC)响应式编程

作者: 小凡凡520 | 来源:发表于2019-10-08 09:22 被阅读0次
    一、简介

    在iOS平台使用响应式编程(Functional Reactive Programming,简称FRP),有一个很好的开源项目ReactiveCocoa,ReactiveCocoa简称RAC,它是基于响应式编程(FRP)思想的Objective-C实践。

    ReactiveCocoa是github开源的一个第三方框架,响应式编程的代表。通过函数式响应式编程的思想,实现的信号机制。使用ReactiveCocoa去搭建MVVM架构,使代码更加高聚合,低耦合。便捷的实现双向绑定的效果。

    二、集成
    • swift项目
    pod 'ReactiveCocoa'
    
    • OC项目
    pod 'ReactiveObjC'
    
    • swift与OC混编
    target 'xxxxxx' do
      # Comment the next line if you don't want to use dynamic frameworks
      use_frameworks!
    
      # Pods for xxxxxx
      pod 'ReactiveObjC'
      pod 'ReactiveCocoa'
      pod 'ReactiveObjCBridge'
    
    end
    
    
    二、UIButton事件监听
    import ReactiveCoccoa
    
    bt.reactive.controlEvents(UIControl.Event.touchUpInside).observeValues { (_) in
       print("test")
    }
    
    三、TextField值变化事件
    import ReactiveCoccoa
    
    
    textFiled.reactive.continuousTextValues.observeValues { (str) in
        print(str)
    }
    
    textFiled.reactive.controlEvents(UIControl.Event.editingChanged).observeValues { (t) in
        print(t.text)
    }
    
    // 输入字符长度大于3
    textFiled.reactive.continuousTextValues.filter { (str) -> Bool in
        let lenth = str.lengthOfBytes(using: String.Encoding.utf8)
        return lenth > 3
        }.observeValues { (text) in
            print(text)
    }
    
    四、RACSiganl信号类
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            // 创建信号
            let singal = RACSignal<AnyObject>.createSignal({ (sub) -> RACDisposable? in
                
                // 信号内部发送数据
                sub.sendNext(1)
                
                // 如果信号被取消,就必须返回一个RACDisposable
                return RACDisposable(block: {
                    print("取消了")
                })
            })
            
            // 只要订阅信号,就会返回一个被动取消信号的类
            let disposable = singal.subscribeNext { (obj) in
                print(obj)
            }
            
            // 主动取消订阅
            disposable.dispose()
        }
    }
    
    五、RACSubject :信号提供者
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            // 创建信号
            let subject = RACSubject<AnyObject>()
            
            // 订阅信号
            subject.subscribeNext { (obj) in
                print(obj)
            }
            
            // 发送信号
            subject.sendNext(123 as AnyObject)
        }
    }
    
    六、RACReplaySubject:重复提供信号类
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            // 创建信号
            let replaySubject = RACReplaySubject<AnyObject>(capacity: 1)
            
            // 第一个订阅信号
            replaySubject.subscribeNext { (obj) in
                print("test1 === \(obj)")
            }
            
            // 第二个订阅信号
            replaySubject.subscribeNext { (obj) in
                print("test2 === \(obj)")
            }
            
            replaySubject.sendNext(123 as AnyObject)
        }
    }
    
    
    七、RACSequence:RAC中的集合类
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            // 必须用OC类
            let numbers:NSArray = [1,2,3,4,5]
            numbers.rac_sequence.signal().subscribeNext { (obj) in
                print(obj)
            }
            
            // 必须用OC类
            let dict:NSDictionary = [
                "name":"chenfan",
                "age":"666"
            ]
            dict.rac_sequence.signal().subscribeNext { (obj) in
                print(obj?.first)
                print(obj?.second)
            }
        }
    }
    
    八、常见用法
    • 代理
    // Student.m
    #import "Student.h"
    
    @implementation Student
        
        - (void)test {
            NSLog(@"sds");
        }
    
    @end
    
    -----------------------------------------------------
    
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            // 注意:Student类必须是OC类才有用!!!!!!!!!
            let student = Student()
            
            // 先注册
            student.rac_signal(for: #selector(Student.test)).subscribeNext { (t) in
                print("test")
            }
            // 后发送指令
            student.test()
        }
    }
    
    • KVO
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Student : NSObject
     
        @property (nonatomic) NSString * name;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    -----------------------------------------------------
    
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            // 注意:Student类必须是OC类
            let p = Student()
            
            // 监听
            p.rac_values(forKeyPath: NSStringFromSelector(#selector(getter: Student.name)), observer: self).subscribeNext { (obj) in
                print(obj)
            }
            
            // 变更
            p.name = "ssssss"
        }
    }
    
    • 监听按钮
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        @IBOutlet weak var bt: UIButton!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            bt.rac_signal(for: UIControl.Event.touchUpInside).subscribeNext { (control) in
                print("test")
            }
        }
    }
    
    • 监听通知
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            NotificationCenter.default.rac_addObserver(forName: UIResponder.keyboardWillShowNotification.rawValue, object: nil).subscribeNext { (noti) in
                print("noti?.name")
            }
        }
    }
    
    • 监听textfield的输入内容
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        @IBOutlet weak var textFiled: UITextField!
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            textFiled.rac_textSignal().subscribeNext { (str) in
                print(str)
            }
        }
    }
    
    • Timer定时器
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            RACSignal<AnyObject>.interval(2 as Double, on: RACScheduler.mainThread()).subscribeNext { (date) in
                print(date)
            }
        }
    }
    
    九、RAC操作方法之映射:flattenMap,Map
    • flattenMap:把源信号的内容映射成一个新的信号,信号可以是任意类型
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            // 创建信号
            let subject = RACSubject<AnyObject>()
            
            // 绑定信号
            let bindSignal = subject.flattenMap { (obj) -> RACSignal<AnyObject>? in
                // 修改源信号
                return RACReturnSignal.return("obj" as AnyObject)
            }
            
            // 订阅绑定信号
            bindSignal.subscribeNext { (obj) in
                print(obj)
            }
            
            subject.sendNext(456 as AnyObject)
        }
    }
    
    • flattenMap实现:信号中信号取值
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            let signalOfsignals = RACSubject<AnyObject>()
            let signal = RACSubject<AnyObject>()
            let bindSignal = signalOfsignals.flattenMap { (obj) -> RACSignal<AnyObject>? in
                return obj as? RACSignal<AnyObject>
            }
            bindSignal.subscribeNext { (obj) in
                print(obj)
            }
            
            signalOfsignals.sendNext(signal)
            signal.sendNext(123 as AnyObject)
        }
    }
    
    • map:把源信号的值映射成一个新的值
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            let subject = RACSubject<AnyObject>()
            let bindSignal = subject.map { (obj) -> Any? in
                return "123"
            }
            bindSignal.subscribeNext { (obj) in
                print(obj)
            }
            subject.sendNext(456 as AnyObject)
        }
    }
    
    十、ReactiveCocoa操作方法之组合
    • concat: 按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            let siganlA = RACSignal<AnyObject>.createSignal { (sub) -> RACDisposable? in
                sub.sendNext("上部分数据")
                sub.sendCompleted()
                return nil
            }
            
            let siganlB = RACSignal<AnyObject>.createSignal { (sub) -> RACDisposable? in
                sub.sendNext("下部分数据")
                return nil
            }
            
            let concatSignal = siganlA.concat(siganlB)
            
            concatSignal.subscribeNext { (obj) in
                print(obj)
            }
        }
    }
    
    • then: 用于连接两个信号,当第一个信号完成,才会连接then返回的信号
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            let siganlA = RACSignal<AnyObject>.createSignal { (sub) -> RACDisposable? in
                sub.sendNext("上部分数据")
                sub.sendCompleted()
                return nil
            }
            
            let siganlB = RACSignal<AnyObject>.createSignal { (sub) -> RACDisposable? in
                sub.sendNext("下部分数据")
                return nil
            }
            
            let thenSiganl = siganlA.then { () -> RACSignal<AnyObject> in
                return siganlB
            }
            thenSiganl.subscribeNext { (obj) in
                print(obj)
            }
        }
    }
    
    • merge:把多个信号合并为一个信号,任何一个信号有新值的时候就会调用
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            let signalA = RACSubject<AnyObject>()
            let signalB = RACSubject<AnyObject>()
            
            let mergeSiganl = signalA.merge(signalB)
            mergeSiganl.subscribeNext { (obj) in
                print(obj)
            }
            
            signalB.sendNext("下部分" as AnyObject)
            signalA.sendNext("上部分" as AnyObject)
        }
    }
    
    • zipWith:把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组,才会触发压缩流的next事件
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            let signalA = RACSubject<AnyObject>()
            let signalB = RACSubject<AnyObject>()
            
            let zipSignal = signalA.zip(with: signalB)
            zipSignal.subscribeNext { (obj) in
                print(obj)
            }
            
            signalA.sendNext(1 as AnyObject)
            signalB.sendNext(2 as AnyObject)
        }
    }
    
    十一、ReactiveCocoa操作方法之过滤
    • filter:过滤信号,使用它可以获取满足条件的信号
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        @IBOutlet weak var text1: UITextField!
        @IBOutlet weak var text2: UITextField!
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            text1.rac_textSignal().filter { (str) -> Bool in
                return (str?.length ?? 0) > 3
                }.subscribeNext { (str) in
                    print(str)
            }
        }
    }
    
    • ignore:忽略完某些值的信号
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            let subject = RACSubject<AnyObject>()
            let ignoreSignal = subject.ignore("1" as AnyObject)
            
            ignoreSignal.subscribeNext { (obj) in
                print(obj)
            }
            
            subject.sendNext("13" as AnyObject)
        }
    }
    
    • distinctUntilChanged:当上一次的值和当前的值有明显的变化就会发出信号,否则会被忽略掉。
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            let subject = RACSubject<AnyObject>()
            subject.distinctUntilChanged().subscribeNext { (obj) in
                print(obj)
            }
            
            subject.sendNext(1 as AnyObject)
            subject.sendNext(1 as AnyObject)
            subject.sendNext(2 as AnyObject)
            subject.sendNext(1 as AnyObject)
        }
    }
    
    • skip:(NSUInteger):跳过几个信号,不接受
    import UIKit
    import ReactiveObjC
    
    class ViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            let subject = RACSubject<AnyObject>()
            subject.skip(2).subscribeNext { (obj) in
                print(obj)
            }
            
            subject.sendNext(1 as AnyObject)
            subject.sendNext(2 as AnyObject)
            subject.sendNext(3 as AnyObject)
        }
    }
    
    十二、RAC常见宏
    • RAC (swift 中不可用)
    #import "ViewController.h"
    #import <ReactiveObjC/ReactiveObjC.h>
    
    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet UILabel *lb;
    @property (weak, nonatomic) IBOutlet UITextField *text1;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        RAC(self.lb, text) = self.text1.rac_textSignal;
    }
    
    
    @end
    
    
    • RACObserve (swift 中不可用)
    #import "ViewController.h"
    #import <ReactiveObjC/ReactiveObjC.h>
    
    @interface ViewController ()
    @property (weak, nonatomic) IBOutlet UILabel *lb;
    @property (weak, nonatomic) IBOutlet UITextField *text1;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        
        [RACObserve(self.text1, frame) subscribeNext:^(id  _Nullable x) {
            NSLog(@"test %@",x);
        }];
        
        self.text1.frame = CGRectMake(0, 0, 100, 100);
    }
    
    
    @end
    
    

    相关文章

      网友评论

          本文标题:ReactiveCocoa(RAC)响应式编程

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