- 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
CustomViewcallsbtnClick, 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'scenterproperty into a signal. Whenever the value changes, the signal fires. -
observer: can benil.
- (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 theSignalsarray have each calledsendNextat least once, the firstselectorparameter'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
signalAandsignalB— 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 aRACTuple. Place the types to pack as macro parameters and they are automatically wrapped. -
RACTupleUnpack: Unpacks aRACTupleinto 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.