R eactiveCocoa code practices-more thoughts, eactivecocoa

Source: Internet
Author: User

ReactiveCocoa code practices-more thoughts, eactivecocoa
Iii. ReactiveCocoa code practices-more thoughts

1. Differences in RACObserve () macro parameters

The difference between RACObserve (self. timeLabel, text) and RACObserve (self, timeLabel. text) has been considered before. Both methods observe the attributes of self. timeLabel. text and can implement functions. It is estimated that the author originally used one of them and later provided support for the other. What is the difference between which method is better?

Click here to see that most of the source code of RACObserve is method calling, and a layer-by-layer click to finally come to this method.

- (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver block:(void (^)(id, NSDictionary *, BOOL, BOOL))block

In this method, the keypath after the comma is separated into an array through. And three attributes are obtained.

BOOL keyPathHasOneComponent = (keyPathComponents.count == 1);NSString *keyPathHead = keyPathComponents[0];NSString *keyPathTail = keyPath.rac_keyPathByDeletingFirstKeyPathComponent;

Here, we will get the keypatch header and the Section for turning around, and we will call ourselves internally in the following method.

// Adds the callback block to the remaining path components on the value. Also// adds the logic to clean up the callbacks to the firstComponentDisposable.void (^addObserverToValue)(NSObject *) = ^(NSObject *value) {    RACDisposable *observerDisposable = [value rac_observeKeyPath:keyPathTail options:(options & ~NSKeyValueObservingOptionInitial) observer:weakObserver block:block];    [firstComponentDisposable() addDisposable:observerDisposable];};
 

In addition, the keyPathTail is passed as the keypatch, which is a recursive call. The first element is cut every time it comes in until the value of BOOL keyPathHasOneComponent is yes. From this perspective, the use of RACObserve (self, timeLabel. text) writing method will lead to recursive calls, the performance is not as good as RACObserve (self. timeLabel. text ).

More RAC macro-related knowledge visible this: http://blog.sunnyxx.com/2014/03/06/rac_1_macros/

2. Set Operations

Assume that there is a demand. There is an array of passwords. If we judge that the password length is too short if it is smaller than 6 characters, a message will be thrown in the system: the XXX password is too short and unqualified. The write method using RAC is more convenient than the conventional writing method. One method filters a custom one and then returns the result directly.

NSArray * pwds = @ [@ "567887", @ "89877", @ "789", @ "7899000"]; RACSequence * results = [[pwds. rac_sequence filter: ^ BOOL (NSString * pwd) {return pwd. length <6;}] map: ^ id (NSString * pwd) {return [[pwd mutableCopy] stringByAppendingString: @ "the password is too short to pass"];}]; NSLog (@ "% @", results. array );

The block code in the filter method in the middle will be executed only when the results. array code below is executed, which is equivalent to executing with a subscriber. This is very similar to RACSignal because signal and sequence are both streams. They share many of the same methods. signal is a push-driven stream and sequence is a pull-driven stream.

If you perform operations when retrieving other attributes from the RACSequence object, you can also use the following method:

RACSequence * s = [RACSequence sequenceWithHeadBlock: ^ id {return @ "Custom operation";} tailBlock: ^ RACSequence * {return [RACSequence new];}]; NSLog (@ "% @", s. head); NSLog (@ "% @", s. tail );

The two blocks are executed only when the specified attribute is called. Note that head is the first element of sequence, while tail removes all the remaining elements of the first element, so it is still a sequence. (Dong Boran blog Park)

3. Signal game skill release

Suppose we now need to use RAC to simulate a method to blow gas in the arcade. After you press the specified button, you will be able to release the first punch.

First, connect the buttons and set a signal to listen to the union of the separate signals of all buttons to capture the title of each button.

// Merge the signals of the six buttons into RACSignal * comboSignal = [[RACSignal merge: @ [[self. topBtn rac_signalForControlEvents: UIControlEventTouchUpInside], [self. bottomBtn rac_signalForControlEvents: UIControlEventTouchUpInside], [self. leftBtn rac_signalForControlEvents: UIControlEventTouchUpInside], [self. rightBtn rac_signalForControlEvents: UIControlEventTouchUpInside], [self. BBtn rac_signalForControlEvents: UIControlEventTouchUpInside], [self. ABtn rac_signalForControlEvents: UIControlEventTouchUpInside] map: ^ id (UIButton * btn) {return btn. currentTitle;}];

Then, buffer the signal source, capture all the key information received every three seconds, and perform judgment and subsequent operations.

// Set the triggering condition NSString * comboCode = @ "prefix and prefix"; // The actual RACSignal * canAction = [[[comboSignal bufferWithTime: 3 onScheduler: [RACScheduler mainThreadScheduler] map: ^ id (RACTuple * value) {return [[value allObjects] componentsJoinedByString: @ ""] ;}] map: ^ id (NSString * value) {return @ ([value containsString: comboCode]) ;}]; // call combo: The method is to release the skill [self rac_liftSelector: @ selector (combo :) withSignalsFromArray: @ [canAction];

The above code can implement the expected function, as long as you can press the specified button within three seconds to release the buffer. However, there is also a problem in this method: After buffer3 seconds is set, the block will only arrive once every three seconds. That is to say, if you have set a skill in 0.5 seconds, it also takes another 2.5 seconds to release the skills. Obviously, this is unacceptable in practice.

So I tried other implementation methods and tried methods such as takeLast:, takeUntilBlock: And scanWithStart:. Finally, I used aggresponwithstart: to meet the requirement.

// Set the triggering condition NSString * comboCode = @ "prefix and prefix"; // actual operation _ time = [[[NSDate alloc] init] timeIntervalSince1970]; [[comboSignal aggresponwithstart: @ "" reduce: ^ id (NSString * running, NSString * next) {if ([[NSDate alloc] init] timeIntervalSince1970]-_ time) <3) {NSString * str = [NSString stringWithFormat: @ "% @", running, next]; return [str containsString: comboCode]? [Self combo]: str;} _ time = [[[NSDate alloc] init] timeIntervalSince1970]; return str. length <combo. length? Str: [str subStringFromIndex: str. length-comboCode. length] ;}] subscribeNext: ^ (id x) {}];

This code can be used to trigger the skill immediately after the button is pressed.

The first parameter of aggresponwithstart: reduce: is the initial value, and the second parameter is a block. The return value of this block is the running parameter that comes to this block next time. The operations I perform in this block loop include:

1. Perform delta computing on the time. If the last time node is greater than 3 seconds away, refresh the time node and re-timer. If str is smaller than 5, return. If str is greater than 5, return the last five digits.

2. If the number is less than 3 seconds, the key information is aggregated into a string and the skill trigger code is included.

3. if the skill is met, the time node of the skill method is refreshed internally and the running is intercepted (the last four digits are retained to prevent the last and next cycles from being completed ). If not, the string is returned.

Although the Code is not very good-looking, but the function is implemented, it feels awkward, because functional programming advocates reference transparency without side effects, therefore, the above practice of recording values and member variables is obviously not suitable for using RAC, and there should be better implementation methods.

4. Other RAC operations

1) ing: flattenMap, Map is used to Map the source signal content into new content

2) combination: concat: concatenates signals in a certain order. When multiple signals are sent, they receive signals in sequence.

3) 'then': used to connect two signals. When the first signal is complete, the signal returned by then is connected.

4) 'merge': merges multiple signals into one signal, which is called when any signal has a new value.

5) 'combinelatest ': merges multiple signals and obtains the latest values of each signal. The merged signal must have at least one sendNext operation before it is triggered.

6) 'reduce' aggregation: The content used for signal sending is a tuples. The values of the sent tuples are aggregated into a value.

7) filter: filter the signal, which can be used to obtain signals that meet the conditions.

8) ignore: ignores signals of some values.

9) distinctUntilChanged: When a value changes significantly with the current value, a signal is sent; otherwise, it is ignored.

10) take: obtains a total of N signals from the beginning.

11) takeLast: gets the last N signals. The subscriber must complete the call based on the prerequisites, because only the completion of the call knows the total number of signals.

12) takeUntil :( RACSignal *): obtains the signal until a signal is executed successfully.

13) skip :( NSUInteger): skip several signals and do not accept

14) switchToLatest: used for signalOfSignals (signal). Sometimes, the signal also sends a signal and obtains the latest signal sent by signalOfSignals in signalOfSignals.

15) doNext: Execute the Block before executing Next.

16) doCompleted: The Block is executed before sendCompleted is executed.

17) deliverOn: The content is transferred to the formulation thread. The side effects are in the original thread. The code in the block when the signal is created is called a side effect.

18) subscribeOn: both content delivery and side effects are switched to the formulation thread.

19) interval timing: signals are sent at intervals.

20) delay delays sending next messages.

21) proxy replacement:

  • Rac_signalForSelector: Used to replace a proxy.

22) replace KVO:

  • Rac_valuesAndChangesForKeyPath: Used to listen for attribute changes of an object.

23) Listener events:

  • Rac_signalForControlEvents: used to listen to an event.

24) replace notification:

  • Rac_addObserverForName: used to listen to a notification.

25) text changes in the listening text box:

  • Rac_textSignal: this signal is sent when the text box changes.

26) only when data is obtained when the interface has multiple requests can the interface be displayed

  • Rac_liftSelector: withSignalsFromArray: Signals: when the input Signals (signal array), each signal must sendNext at least once, it will trigger the method of the first selector parameter.
  • Note: For a few signals, the method of parameter 1 involves several parameters. Each parameter corresponds to the data sent by the signal.

 

RAC was once hailed as a poor evaluation of learning costs, poor readability, and debug. However, with the evolution in recent years, RAC has gradually been accepted by enterprise-level projects and has become a mainstream framework for functional responsive programming. RAC employs more and more people, as well as more essays and blogs. The learning threshold has been greatly reduced. In addition, I don't think it is necessary for beginners to understand all the operations and concepts from the very beginning. They can begin with simple usage and step-by-step access to higher-order syntaxes, which makes it easier to accept.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.