Page 1
Pavlo Zakharov
Reactive Cocoa: Paradigm shift.
- What is Reactive functional Paradigm?- Why consider using ReactiveCocoa?- RAC Signal.Unifying all of Cocoa’s common patterns.- RAC and concurrency.- Implementing MVVM design pattern on iOS with RAC.
Page 2
What is Reactive Functional Programming?
Page 3
Functional reactive programming (FRP) is a programming paradigm for reactive programming (asynchronous dataflow programming) using
the building blocks of functional programming (e.g. map, reduce, filter). FRP has been used for programming graphical user interfaces (GUIs), robotics, and music, aiming to simplify these problems by explicitly
modelling time. (c) Wikipedia
Page 4
Reactive+Functional:
❖ Static/Dynamic data flow.(Programming based on Events)
❖ (Functional Blocks) Functions passed as arguments to functions.
Page 5
Cocoa Events
❖ Delegation❖ KVO❖ Target - Action❖ Callback Blocks❖ NSNotifications}RacSignal
Page 6
RACSignal
❖ Next❖ Error❖ Completed
Ray Signal emits:
[self.searchText.rac_textSignal subscribeNext:^(id x) { NSLog(@"Next ocured"); }error:^(NSError *error) { NSLog(@"Error ocured"); }completed:^{ NSLog(@"Completed"); }];
Signal can have one or multiple subscribers
Page 7
EventsEvent flow:
CompletedCompleted
NextNext
NextNext
NextNext ErrorError
NextNext NextNext …
Page 8
Reactive Operations
❖ Map❖ Throttle❖ Skip❖ Filter❖ DeliverOn❖ more…
Page 9
Operations don’t care about signal source.
Page 10
Map
❖ Transforms the value of the event(As transformed value as input signal can be literally anything)
RACSignal *mySignal = [textSignal map:^id(NSString *text) { return @(text.length>3); }];[mySignal subscribeNext:^(NSNumber* x) { if ([x boolValue]) { //... } }];
Page 11
Combine
❖ Combines two RAC Events(Next Emits when one of combined events occurs).
RACSignal *switch1Signal = … RACSignal *switch2Signal = …
RACSignal *both = [RACSignal combineLatest:@[switch1Signal,switch2Signal] reduce:^id(NSNumber *switch1, NSNumber *switch2){ return @([switch1 boolValue] && [switch2 boolValue]); }]; [both subscribeNext:^(id x) { if([x boolValue]){ NSLog(@"Both"); } }];
Page 12
Filter
❖ Event will be emitted only if the condition is satisfied.
[[self.usernameTextField.rac_textSignal filter:^BOOL(id value) { return (((NSString*)value).length>3); }]subscribeNext:^(id x) { NSLog(@"do stuff"); }];
Page 13
Throttle
❖ If event occurrence once more within time interval specified event wouldn’t be emitted.(Extremely useful for locking buttons to prevent speed clicking)
[[[self.usernameTextField.rac_textSignal filter:^BOOL(id value) { return (((NSString*)value).length>3); }]throttle:0.5]subscribeNext:^(id x) { NSLog(@"do stuff"); }];
Page 14
Deliver On
❖ The block will be executed on thread specified (For example for UI stuff on main thread)
[[[self.usernameTextField.rac_textSignal filter:^BOOL(id value) { return (((NSString*)value).length>3); }] deliverOn:[RACScheduler mainThreadScheduler]]subscribeNext:^(id x) { NSLog(@"do UI stuff"); }];
Page 15
How to mix reactive code with non-reactive?
Page 16
Option one: doNext block
❖ doNext Block will be executed before subscriberBlock will be called.This is the good place for reactive code.
[[[self.signInButton rac_signalForControlEvents:UIControlEventTouchUpInside] doNext:^(id x) { //put your non-reactive code here }] subscribeNext:^(NSNumber *signedIn) { //do stuff }];}
Page 17
Wrap non-reactive code to reactive
❖ Method will create signal which can emit next/error/completed event based on your non-reactive conditions.
-(RACSignal *)switchSignal{ return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { (self.switch1.isOn)?[subscriber sendNext:@(YES)] : [subscriber sendNext:@(NO)]; return nil; }];} //. //. //. [[self switchSignal]subscribeNext:^(id x) { //doStuff }];
Page 18
Bind Signal to UIEvent
❖ Every time touchUpInside event occurs next event will be emitted;
RACSignal *mySignal = [self.getButton rac_signalForControlEvents:UIControlEventTouchUpInside]
Page 19
Avoid Retain cycles
❖ Accessing self in block can cause retain cycle and memory leak.Use __weak self to prevent it.
@weakify(self); [self.searchText.rac_textSignal subscribeNext:^(id x) { @strongify(self); // self.smth = smth }error:^(NSError *error) { @strongify(self); // self.smthElse = smth }completed:^{ @strongify(self); // self.smthReallyDifferent = smth }];
Page 20
ModelViewViewModel
Page 21
ViewModel
❖ ViewModel which is a special type of model that represents the UI state of the application
ViewView ViewModeViewModell ModelModel
ViewView ViewModeViewModell ModelModel
ControllControllerer
Page 22
Binding
❖ Binds textField.text to the property in ViewModel. Every time property changes text will change as well. (WPF implementation is shown on the right)
RAC(self.searchText,text) = self.myString;
<TextBlock TextContent=”{Binding Path=Description}” />~
Page 23
Why should i use RAC?
❖ Unified interface for all Cocoa events.❖ Less code in comparison with non-reactive code.❖ No massive ViewControllers with complicated
relationships.❖ Easy work with concurrency.❖ No complicated “States” needed.
Page 24
Some Disadvantages❖ Debug Hell.❖ Little overhead❖ Weird syntax.(But you will get used to it)
Page 25
Resources
❖ https://github.com/ReactiveCocoa/ReactiveCocoa
❖ http://www.raywenderlich.com❖ http://blog.scottlogic.com/2014/07/24/mvvm-rea
ctivecocoa-swift.html❖ https://www.youtube.com/watch?v=DgdISd1Qc4
8❖ https://www.youtube.com/watch?v=fWV7xyN5C
R8❖ https://github.com/ZakharovPaul/RacDemo.git
Page 27
Thank you Skype: c1ark.E-mail: [email protected]