Reactive Cocoa Learning Chapter

Keywords: Attribute Programming

Reprint address: http://www.jianshu.com/p/05544e4ac972

1. What are the common usages in Reactive Cocoa development?

Type 1: Substitution of Agent

rac_signalForSelector: Used as an alternative agent

// 1. Replacing Agent, RACSubject
    // RAC method: It can be judged whether a method is called or not.
    // As long as self calls Selector, a signal is generated
    // rac_signalForSelector: Listening for an object to call a method
    [[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(id x) {

        NSLog(@"Controller called didReceiveMemoryWarning");
    }];
    // Judging if redView calls btnClick means clicking the button
    [[_redView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
        NSLog(@"Click the button");
    }];

Type 2: Replacing KVO

rac_valuesAndChangesForKeyPath: Used to listen for property changes of an object

 [_redView rac_observeKeyPath:@"name" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
        // As soon as the listener's attributes change the call
        NSLog(@"%@",_redView.name);
    }];

    // KVO: Second, as long as the value of the object changes, it generates a signal, a subscription signal.
    [[_redView rac_valuesForKeyPath:@"name" observer:nil] subscribeNext:^(id x) {

    }];

Category 3: Monitoring events

Rac_signal ForControl Events: Used to listen for an event

 //  As long as the button generates this event, it generates a signal.
    [[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {

        NSLog(@"The button is clicked%@",x);
    }];
    _btn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        NSLog(@"Button Click");
        return [RACSignal empty];
    }];

Type 4: Substitution of Notification

Rac_addObserver ForName: Used to listen for a notification

    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {

        NSLog(@"%@",x);
    }];

Category 5: Listening for Text Box Text Change

rac_textSignal: This signal is emitted whenever the text box changes

    [_textField.rac_textSignal subscribeNext:^(id x) {
        // x: Text box text
        NSLog(@"%@",x);
    }];

Sixth: Processing the interface when it has multiple requests and needs to get data before it can be displayed

Ra_lift Selector: With Signals FromArray: Signals: When the incoming Signals (signal array), each signal has sendNext at least once, it triggers the method of the first selector parameter.

  RACSignal *requestHot = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"Request the hottest merchandise");
        [subscriber sendNext:@"Access to the hottest commodities"];
        return nil;
    }];

    RACSignal *requestNew = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"Request for the latest merchandise");
//        [subscriber sendNext:@ Get the latest product];
        return nil;
    }];

    // Selector call: Called when all signals send data
    // Array Storage Signal
    // Selector Note: Parameters are determined by array elements
    // The parameter type of the Selector method is the data transmitted by the signal.
    [self rac_liftSelector:@selector(updateUI:data2:) withSignalsFromArray:@[requestHot,requestNew]];

}
// Called only when both requests have been completed
- (void)updateUI:(NSString *)data1 data2:(NSString *)data2
{
    NSLog(@"%@ %@",data1,data2);
}

2. Common macros of ReactiveCocoa

First

RAC(TARGET, [KEYPATH, [NIL_VALUE]]): Used to bind an attribute of an object

    // To bind a signal to an object's attribute, as long as the signal is generated, the content of the signal is assigned to the object's attribute.
    // Bind a signal to label's text attribute
    RAC(_label,text) = _texfField.rac_textSignal;

Second

RACObserve(self, name): Listens for an attribute of an object and returns a signal.

    // Observing a property of an object
    [RACObserve(self, name) subscribeNext:^(id x) {

        NSLog(@"%@",x);
    }];

Third

@ Weak ify (Obj) and @strongify(Obj) are commonly used together to solve the problem of circular reference.

Fourth

RACTuplePack: Packing data into RACTuple (tuple class)

    // RACTuplePack: Quickly pack some data into tuple classes
    RACTuple *tuple = RACTuplePack(@"123",@1);

Fifth

RACTupleUnpack: Unpack RACTuple (tuple class) into corresponding data

    // Parameter: The name of the variable that needs to be parsed and generated
    RACTupleUnpack(NSString *str,NSNumber *num) = tuple;

    NSLog(@"%@ %@",str,num);

3. Common operating methods of ReactiveCocoa

  • ReactiveCocoa Operating Principle
    All signals (RACSignal) can be manipulated, because all methods of operation are defined in RACStream.h, so as long as RACStream is inherited, there are manipulation methods.

  • Reactive Cocoa Operational Thought
    Hook is a technology used to change the execution result of API (application programming interface: method). Hook is used to intercept API calls. Hook Principle: Before each call to an API to return a result, first execute your own method and change the output of the result

  • ReactiveCocoa Core Method Bid
    The core method of ReactiveCocoa operation is bind (binding), and the core development method in RAC is also binding. The former development method is assignment, and RAC development should focus on binding, that is, when creating an object, we can bind what we want to do in the future, rather than after equal assignment. Do something

The Use of Core Method Bid

  RACSignal *bindSignal = [_textField.rac_textSignal bind:^RACStreamBindBlock{
        // block call time: Called whenever a signal is bound. Indicates that the signal binding is complete

        NSLog(@"Source signal is bound");
        return ^RACStream *(id value, BOOL *stop){
            // When is RACStreamBindBlock invoked: Every time the source signal sends out the content, the block is invoked

            // value: The content of the source signal
            NSLog(@"Content of Source Signal:%@",value);

            // RACStream Bind block Role: Processing the Content of Source Signals in this block
            value = [NSString stringWithFormat:@"xmg%@",value];
            // block return value: signal (wrapping the processed value into a signal and returning it)

            // Create a signal, and the value of the signal is the value we have processed.
            return [RACReturnSignal return:value];
        };

    }];

    // Subscription Binding Signal, not Source Signal
    [bindSignal subscribeNext:^(id x) {

        NSLog(@"%@",x);
    }];
    // Execution process
    /*
        1. Text Change Source Signal
        2. Binding source signal, [_textField.rac_textSignal bind]
        * Call bind to return the bound signal, didSubscribe
        3. Subscription Binding Signal
            * Create Subscribers
            * didSubscribe calling the bound signal
        4. Execute the binding signal didSubscribe
        5. Execute the block passed in by the bind method
        6. Subscriber Signal
        7. As soon as the source signal sends out the content, it calls ID signal = bindingBlock (x, & stop);
            * signal: signal that processes the value

     */

Mapping of Reactive Cocoa Operational Methods (Map)

flattenMap: Signal in Signal, signalOfSignals

[[_textField.rac_textSignal flattenMap:^RACStream *(id value) {
        // value: Content of the source signal
        value = [NSString stringWithFormat:@"xmg%@",value];
        // Return value: signal, wrapping the processed value into a signal and returning it
        return [RACReturnSignal return:value];
    }] subscribeNext:^(id x) {
        // Subscription [RACReturnSignal return:value send value

        // x: The value of the bound signal
        NSLog(@"%@",x);
    }];

map: For ordinary signals, signals emit common values

  [[_textField.rac_textSignal map:^id(id value) {
        // value: Content of the source signal
        // The return value is to process the content of the source signal and return it directly.
        return [NSString stringWithFormat:@"----xmg%@",value];

    }] subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];

The difference between FlatternMap and Map

  • 1. Block return signal in FlatternMap.
  • 2. Block return object in Map.
  • 3. In development, Map is generally used for mapping if the value of the signal is not a signal.
  • 4. In development, FlatternMap is generally used for mapping if the value of the signal is a signal.

Combination of ReactiveCocoa Operating Methods

concat: Splice the signals in a certain order. When multiple signals are sent, the signals are received sequentially.

 // Conat: Connecting signals, sequential splicing, must wait for the first signal to complete, the second signal will be activated.
    RACSubject *signalA = [RACSubject subject];
    RACSubject *signalB = [RACSubject subject];

    // Combination signal
    RACSignal *signals = [signalA concat:signalB];

    // Subscription Combination Signal
    [signals subscribeNext:^(id x) {

        NSLog(@"%@",x);
    }];

    // send data
    [signalA sendNext:@1];
    [signalA sendCompleted];
    [signalB sendNext:@2];

then: Used to connect two signals. When the first signal is completed, the signal returned from the n will be connected.

 RACSubject *signalA = [RACSubject subject];
    RACSubject *signalB = [RACSubject subject];

    // combination
    RACSignal *signals = [signalA then:^RACSignal *{
        return signalB;
    }];

    [signals subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];

    [signalA sendNext:@1];
    [signalA sendCompleted];
    [signalB sendNext:@2];
 The difference between "then" and "concat" is that the value of the first signal cannot be monitored. The common point is that the first signal must be completed before the second signal can be activated.

merge: merge multiple signals into one signal, and any signal will be called when it has a new value.

// merge: merge, any signal can subscribe as long as it sends a value
    RACSubject *signalA = [RACSubject subject];
    RACSubject *signalB = [RACSubject subject];

    RACSignal *signals = [signalA merge:signalB];

    [signals subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];

    [signalA sendNext:@1];

    [signalB sendNext:@2];

    [signalB sendNext:@3];

zipWith: Compresses two signals into one signal. next events of compressed streams are triggered only when two signals simultaneously emit the content of the signal and merge the content of the two signals into one tuple.

RACSubject *signalA = [RACSubject subject];
    RACSubject *signalB = [RACSubject subject];

    RACSignal *signals = [signalA zipWith:signalB];

    [signals subscribeNext:^(id x) {

        NSLog(@"%@",x);
    }];

    // zipWith: When both signals send out content, they can be subscribed to
    [signalA sendNext:@1];
    [signalB sendNext:@2];

    [signalB sendNext:@3];
    [signalA sendNext:@4];

Combine Latest: Combine multiple signals and get the latest values of each signal. Each combined signal must have sendNext at least once before it can trigger the combined signal.

  // The first parameter is to store the signal that needs to be merged.
    [[RACSignal combineLatest:@[_textField1.rac_textSignal,_textField2.rac_textSignal] reduce:^id(NSString *str1,NSString *str2){
        NSLog(@"%@ ---- %@",str1,str2);
        // block: As long as any signal sends out the content, it will be called
        // Number of block parameters: determined by signal
        // block parameter type: block parameter is the signal emitted value
        // Which values are aggregated from the two signals?
        return @(str1.length && str2.length);
    }] subscribeNext:^(id x) {
        _btn.enabled = [x boolValue];
        NSLog(@"%@",x);
    }];

reduce aggregation: The content used for signaling is tuples, which aggregate the values of the signaling tuples into one value.

    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

        [subscriber sendNext:@1];

        return nil;
    }];

    RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {

        [subscriber sendNext:@2];

        return nil;
    }];

    // polymerization
    // Common usage (first combined in aggregation). CombineLatest: (id < NSFast Enumeration >) signals reduce: (id (^) ()) reduce Block
    // block in reduce:
    // The parameters in reduceblcok, the number of signal combinations, the number of parameters in reduceblcok, each parameter is the content of the previous signal.
    // Reducblcok's return value: the content after the aggregated signal.
  RACSignal *reduceSignal = [RACSignal combineLatest:@[signalA,signalB] reduce:^id(NSNumber *num1 ,NSNumber *num2){

       return [NSString stringWithFormat:@"%@ %@",num1,num2];

   }];

    [reduceSignal subscribeNext:^(id x) {

        NSLog(@"%@",x);
    }];

Filtration of Reactive Cocoa Operation Method

  • filter: filter the signal, and use it to get the signal that meets the requirement
  • ignore: A signal that ignores certain values
  • Distinct UntilChanged: Signals are sent when there is a significant change in the last value and the current value, otherwise they will be ignored.
  • take: take a total of N signals from the beginning
  • takeLast: Take the last N signals, the premise is that the subscriber must call it to complete, because only when it's done, you know how many signals there are in total.
  • takeUntil:(RACSignal *): Get the signal until the signal is executed
  • Skp:(NSUInteger): Skip several signals and don't accept them.
  • switchToLatest: Used for signalOfSignals. Sometimes the signal also sends out a signal. In signalOfSignals, it gets the latest signal sent by signalOfSignals.

Order of Reactive Cocoa Operating Method

  • doNext: This Block is executed before Next is executed
  • doCompleted: This Block is executed before sendCompleted is executed

Thread of ReactiveCocoa Operating Method

  • deliverOn: Content delivery switches to the formulation thread, with side effects in the original thread, calling the code in the block when creating the signal a side effect
  • subscribeOn: Both content delivery and side effects are switched to the formulation thread

Time of ReactiveCocoa Operating Method

  • timeout: timeout allows a signal to automatically report an error after a certain period of time
  • interval Timing: Signaling at intervals
  • delay: Delayed sending next

Repetition of Reactive Cocoa Operating Method

  • Retry retry: If it fails, the block in the created signal will be re-executed until it succeeds
  • Reply playback: When a signal is subscribed to multiple times, the content is played over and over again
  • Throttle throttle: When a signal is sent more frequently, throttle can be used. It does not send the content of the signal for a certain period of time, and after a period of time, it acquires the latest content of the signal and sends it out.

4. Learning MVVM Architecture

  • (1) Why does a program need to be structured?
    Easy for programmers to develop and maintain code
  • (2) What are the common architectural ideas?
    • MVC - -- M: Model V: View C: Controller
    • MVVM--M: Model V: View + Controller VM: View Model
    • MVCS - -- M: Model V: View C: Controller S: Service Class
    • VIPER - -- V: View I: Interactor P: Display E: Entity R: Routing
  • (3)MVVM Thought
    • Model (M): Save view data
    • View + Controller (V): Display Content + How to Display
    • View Model (VM): Processing business logic displayed, including button clicks, data requests and parsing

Posted by jonskinny12 on Mon, 01 Jul 2019 15:01:53 -0700