Published on

ReactiveCocoa Usage and Macros

Common Usage

As mentioned earlier, RAC can replace delegates, KVO, and more. Let's look at the specific usage.

Replacing Delegates:

  • rac_signalForSelector: Used to replace delegates.

  • How it works: It monitors whether a method has been called. When it is called, a signal is automatically emitted.

  • Use case: Custom CustomView — listen for button taps inside the custom view.

  • Previously, you would need a delegate property on the custom view and call the delegate when the button is tapped.

  • rac_signalForSelector: Converts the invocation of a method on an object into a signal. Whenever that method is called, the signal fires.

  • In this example, whenever CustomView calls btnClick, a signal is emitted — just subscribe to it.

Code:

//CustomView
- (IBAction)buttonDidClick:(UIButton *)sender {
    NSLog(@"buttonDidClick");
}

//DelegateViewController
[[self.customView rac_signalForSelector:@selector(buttonDidClick:)] subscribeNext:^(id x) {
    NSLog(@"Controller knows: button was tapped");
}];
2016-03-20 22:43:17.731 RACDemo[46034:5333662] buttonDidClick
2016-03-20 22:43:17.737 RACDemo[46034:5333662] Controller knows: button was tapped

Replacing KVO:

  • rac_valuesAndChangesForKeyPath: Used to monitor property changes on an object.

  • The receiver: the object being observed.

  • KeyPath: the property to observe.

  • Converts changes to redV's center property into a signal. Whenever the value changes, the signal fires.

  • observer: can be nil.

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor randomColor];

    Cat *cat = [Cat new];
    self.cat = cat;

    [[self.cat rac_valuesAndChangesForKeyPath:@"age" options:NSKeyValueObservingOptionNew observer:nil]  subscribeNext:^(id x) {
        NSLog(@"%@", x);
    }];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.cat.age += 1;
}
2016-03-21 10:18:26.130 RACDemo[46460:5399402] <RACTuple: 0x17400e460> (
    5,
        {
        kind = 1;
        new = 5;
    }
)

Listening to Events:

  • rac_signalForControlEvents: Used to listen for a specific control event.

  • Converts a button tap event into a signal. When the button is tapped, the signal fires.

[[self.button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {

        NSLog(@"Button was tapped");
    }];
2016-03-21 10:34:02.781 RACDemo[46512:5404121] Button was tapped

Replacing Notifications:

  • rac_addObserverForName: Used to listen for a specific notification.

  • Whenever the notification is posted, it converts into a signal.

[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
   NSLog(@"Keyboard will show");
}];
2016-03-21 10:42:13.226 RACDemo[46545:5406463] Keyboard will show

Listening to Text Field Changes:

  • rac_textSignal: Emits a signal whenever the text field's content changes.

  • Gets the signal for text field text changes.

[self.textfield.rac_textSignal subscribeNext:^(id x) {
   NSLog(@"%@", x);
}];
2016-03-21 10:45:44.464 RACDemo[46557:5407311] r
2016-03-21 10:45:44.743 RACDemo[46557:5407311] rr
2016-03-21 10:45:44.960 RACDemo[46557:5407311] rrh

liftSelector

  • Use case: When an interface has multiple requests, you want to wait until all data has been received before displaying the UI.

  • rac_liftSelector:withSignalsFromArray:Signals: — when all signals in the Signals array have each called sendNext at least once, the first selector parameter's method is triggered.

  • Usage note: the number of signals must match the number of parameters in the selector method; each parameter corresponds to the value emitted by its respective signal.

  • You don't need to manually subscribe to signalA and signalB — the method handles that internally.

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor randomColor];

    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        double delayInSeconds = 2.0;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [subscriber sendNext:@"A"];
        });
        return nil;
    }];

    RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"B"];
        [subscriber sendNext:@"Another B"];
        [subscriber sendCompleted];
        return nil;
    }];

    [self rac_liftSelector:@selector(doA:withB:) withSignals:signalA, signalB, nil];
}

- (void)doA:(NSString *)A withB:(NSString *)B {
    NSLog(@"A:%@ and B:%@", A, B);
}
2016-03-21 11:11:17.527 RACDemo[46668:5415565] A:A and B:Another B

Common RAC Macros

RAC(TARGET, [KEYPATH, [NIL_VALUE]])

  • Used to bind a property of an object. Binds a signal to an object's property — whenever the signal emits a value, the property is assigned that value.

  • The example below keeps the label's text in sync with the text field's content.

RAC(self.label, text) = self.textField.rac_textSignal;

RACObserve(self, name)

  • Used to bind to a property of an object.

  • Quickly observe changes to a specific property on an object.

  • Returns a signal that fires whenever that property changes.

[RACObserve(self.view, center) subscribeNext:^(id x) {
   NSLog(@"%@", NSStringFromCGRect(self.textField.frame));
}];
2016-03-21 11:25:47.710 RACDemo[46722:5419085] { {198, 156}, {205, 30} }

RACTuplePack and RACTupleUnpack

  • RACTuplePack: Wraps data into a RACTuple. Place the types to pack as macro parameters and they are automatically wrapped.

  • RACTupleUnpack: Unpacks a RACTuple into the corresponding data. The right side of the equals sign is the tuple to unpack. The macro's parameters specify the types to unpack into.

RACTuple *tuple = RACTuplePack(@1,@3);
NSLog(@"%@", tuple);

RACTupleUnpack(NSNumber *num1,NSNumber *num2) = tuple;
NSLog(@"%@ %@", num1, num2);
2016-03-21 11:28:32.712 RACDemo[46736:5420042] <RACTuple: 0x17400c4d0> (
    1,
    3
)
2016-03-21 11:28:32.713 RACDemo[46736:5420042] 1 3

Code:

All code from this article can be found on my GitHub at RACDemo.