Introduction of the RAC

What is ReactiveCocoa?

ReactiveCocoa (RAC for short) is a new framework for iOS and OS X development that is open source at Github. RAC has the characteristics of functional programming (FP) and responsive programming (RP). It is based on the design and implementation of.NET Reactive Extensions.

ReactiveCocoa aims to “stream of values over time”, a stream of data that flows continuously over time.

ReactiveCocoa addresses the following issues:

  • UI data binding

    • UI controls usually need to be bound to an event, and RAC makes it easy to bind any data flow to the control.
  • User interaction event binding

    • RAC provides a series of methods for interactive UI controls to send a Signal. These streams of data are passed from one user to another during user interactions.
  • Solve the problem of states and too many dependencies between states

    • With RAC binding, you don’t have to worry about complex states, isSelect, isFinish… It also solves the problem that these states are difficult to maintain in the later stage.
  • Great unity of messaging mechanisms

    • OC programming in the original messaging mechanism has the following: There is an article about how to select the Delegate, Block Callback, target-Action, Timers, KVO, and OBJC messaging methods in OC. It is recommended to read the article Communication Patterns. Now that RAC is in place, all five of these approaches can be handled uniformly with RAC. In fact, these are the following messaging mechanisms. RAC is packaged in a unified way to make it easier to use.

Common methods for RAC

1. Inform NSNotificationCenter

  • longhand
    • Add keyboard pop-up notification addObserver
    [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillShow:)
                                                     name:UIKeyboardWillShowNotification
                                                   object:nil];
    Copy the code
    • Implementation method
    - (void) keyboardWillShow:(NSNotification *)note {NSLog(@" keyboard is up "); }Copy the code
    • Remove the notification
    - (void)dealloc
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    }
    Copy the code
  • RAC writing
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
        NSLog(@"%@",x);
    }];
    Copy the code
    • The printout of x
    NSConcreteNotification 0x6000000c5170 {name = UIKeyboardWillShowNotification; userInfo = {
    UIKeyboardAnimationCurveUserInfoKey = 7;
    UIKeyboardAnimationDurationUserInfoKey = "0.25";
    UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {390, 336}}";
    UIKeyboardCenterBeginUserInfoKey = "NSPoint: {195, 1012}";
    UIKeyboardCenterEndUserInfoKey = "NSPoint: {195, 676}";
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 844}, {390, 336}}";
    UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 508}, {390, 336}}";
    UIKeyboardIsLocalUserInfoKey = 1;
    }}
    Copy the code

2.KVO

  • longhand

    • model
    @interface TestModel : NSObject
    @property (assign, nonatomic) int age;
    @property (assign, nonatomic) int height;
    @end
    
    Copy the code
    #import "KVOViewController.h" #import "TestModel.h" @interface KVOViewController () @property (strong, nonatomic) TestModel *testModel1; @end @implementation KVOViewController - (void)viewDidLoad { [super viewDidLoad]; self.testModel1 = [[TestModel alloc] init]; self.testModel1.age = 1; self.testModel1.height = 11; / / to add KVO testModel1 objects to monitor when KVO to monitor the age attribute changes NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld; [self.testModel1 addObserver:self forKeyPath:@"age" options:options context:@"123"]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { self.testModel1.age = 20; self.testModel1.height = 30; } // When the value of the property of the listener changes, - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {NSLog(@" listening to %@ value changed - %@ - %@", object, keyPath, change, context); } - (void)dealloc { [self.testModel1 removeObserver:self forKeyPath:@"age"]; [self.testModel1 removeObserver:self forKeyPath:@"height"]; }Copy the code
    • RAC writing

    #define RACObserve(TARGET, KEYPATH) _RACObserve(TARGET, KEYPATH)

    [RACObserve(self.testModel1, age)subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    Copy the code

3. The agent for the Delegate

  • longhand
1. Follow the proxy <UITextFieldDelegate> 2. Space @Property (weak, nonatomic) IBOutlet UITextField *textField; Self. TextField. Delegate = self; 4. The proxy method - (void) textFieldDidBeginEditing: (UITextField at *) textField {NSLog (@ "start editing"); }Copy the code
  • RAC writing
    self.textField.delegate = self;
    
   [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] subscribeNext:^(RACTuple * _Nullable x) {
        NSLog(@"%@",x);
    }];
    
    
    <RACTuple: 0x600000dd9130> (
    "<UITextField: 0x127d0bf90; frame = (97 118; 220 34); text = ''; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x6000001e6f70>; borderStyle = RoundedRect; background = <_UITextFieldSystemBackgroundProvider: 0x600000f8eb80: backgroundView=<_UITextFieldRoundedRectBackgroundViewNeue: 0x127d0e710; frame = (0 0; 220 34); opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x600000f8ec60>>, fillColor=<UIDynamicModifiedColor: 0x6000001874e0; contrast = normal, baseColor = <UIDynamicSystemColor: 0x600001a9bb40; name = systemRedColor>>, textfield=<UITextField 0x127d0bf90>>; layer = <CALayer: 0x600000fe3ee0>>"
)
Copy the code

4.Target-Action

  • longhand
[self.button addTarget:self action:@selector(Click:) forControlEvents:UIControlEventTouchUpInside]; - (void)Click (UIButton *)sender {NSLog(@" button clicked "); }Copy the code
  • RAC
[[self.button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) { NSLog(@"%@",x); }]; <UIButton: 0x15a50d9f0; frame = (101 240; 213, 205); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x60000262fb60>>Copy the code

5.UITextField

  • RAC writing:
[self.textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
    NSLog(@"%@",x);
}];
Copy the code
When I type h in the self.textField, 2019-05-16 18:02:58.562309+0800 001-- RAC[54530:4536864] h 2019-05-16 18:02:59.049225+0800 001-- RAC[54530:4536864] hh 2019-05-16 18:02:59.288995+0800 001-- RAC[54530:4536864] HHHCopy the code

6. Hand gestures

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
self.label.userInteractionEnabled = YES;
[self.label addGestureRecognizer:tap];
[tap.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
    NSLog(@"%@",x);
}];
Copy the code

7. Array and dictionary traversal

  • An array of
TestModel *model1 = [[TestModel alloc] init];
model1.age = 1;
model1.height = 11;

TestModel *model2 = [[TestModel alloc] init];
model2.age = 2;
model2.height = 22;


TestModel *model3 = [[TestModel alloc] init];
model3.age = 3;
model3.height = 33;

NSArray *array = @[model1,model2,model3];
[array.rac_sequence.signal subscribeNext:^(TestModel * _Nullable x) {
    NSLog(@"%d",x.age);
}];
Copy the code
  • The dictionary
NSDictionary * dict = @ {@ "name:" @ "all that much," @ "age" : @ "20" @ "sex" : @ "male"}; [dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {// NSLog(@"%@",x); RACTwoTuple *tuple = (RACTwoTuple *)x; NSLog(@"key == %@ , value = %@",tuple[0],tuple[1]); }];Copy the code

8. Timer

  • NSTimer
NSTimer * timer = [NSTimer timerWithTimeInterval: 30.0 target: self selector: @ the selector (timerFired:) the userInfo: nil repeats:YES]; // Need to add manual RunLoop, It is important to note the NSTimer self is strong references during the period of work [[NSRunLoop currentRunLoop] addTimer: _timer forMode: NSRunLoopCommonModes]; // Use NSRunLoopCommonModes to ensure that the NSTimer works properly when the RunLoop switching mode is used. - (void)stopTimer {if (_timer) {[_timer invalidate]; }}Copy the code
  • RAC
[[RACSignal Interval :2.0 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * _Nullable x) { NSLog(@"%@",x); NSLog(@"%@",[NSThread currentThread]); }]; - the child thread [[RACSignal interval: 2.0 onScheduler: [RACScheduler schedulerWithPriority: RACSchedulerPriorityHigh name: @ "ABC"]] subscribeNext:^(NSDate * _Nullable x) { NSLog(@"%@",[NSThread currentThread]); }];Copy the code

expand

  • The array convenience is that the statements inside the Block are executed first and the statements outside the Block are executed first

Using the fence function to complete the task scheduling

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { TestModel *model1 = [[TestModel alloc] init]; model1.age = 1; model1.height = 11; TestModel *model2 = [[TestModel alloc] init]; model2.age = 2; model2.height = 22; TestModel *model3 = [[TestModel alloc] init]; model3.age = 3; model3.height = 33; NSArray *array = @[model1,model2,model3]; dispatch_queue_t concurrentQueue = dispatch_queue_create("com.concurrent", DISPATCH_QUEUE_CONCURRENT); NSLog(@"🔞 START: %@", [NSThread currentThread]); dispatch_async(concurrentQueue, ^{ [array.rac_sequence.signal subscribeNext:^(TestModel * _Nullable x) { NSLog(@"%@",[NSThread currentThread]); NSLog(@"%d",x.age); }]; }); // ⬅️ task 1 dispatch_barrier_async(concurrentQueue, ^{sleep(3); NSLog (@ "🚥 🚥 % @", [NSThread currentThread]); }); // ⬅️ Barrie task dispatch_async(concurrentQueue, ^{NSLog(@"111")); }); / / ⬅ ️ task 4 NSLog (@ "🔞 END: % @", [NSThread currentThread]); }Copy the code