SlideShare a Scribd company logo
REACTIVE COCOA & MVVM
Николай Касьянов
REACTIVE COCOA
•

Objective-C framework for processing and composing streams	


•

Unifies async Cocoa patterns: callbacks, delegates, KVO,
notifications	


•

Very composable	


•

Helps to minimize state	


•

Inspired by Reactive Extensions for .NET
CALLBACK HELL
void (^completion)(UIImage *) = ...
id token = [self loadImage:url completion:^(NSData *data, NSError *error) {
if (data == nil) {
completion(defaultImage);
}
else {
[self unpackImageFromData:data completion:^(UIImage *image) {
if (image == nil) { // unpacking failed
completion(defaultImage);
}
else {
completion(image);
}
}]
}
}];

!

// client code
[imageLoader cancel:token];

!
FUTURES
•

Future can either complete with a value or reject
with an error	


•

JavaScript Promises/A+	


•

There are some Objective-C implementations	


•

RAC can into futures too
RACSignal *image =
[[[self rac_imageFromURL:url] flattenMap:^(NSData *data) {
return [self rac_unpackedImageFromData:data];
}]
catchTo:[RACSignal return:defaultImage]];

!

// client code:
RAC(cell.imageView, image) =
[image takeUntil:cell.rac_prepareForReuseSignal];
RACSignal
•

A stream of values	


•

One can subscribe to new value, error or completion	


•

Supports functional constructs: map, filter, flatMap, reduce
etc	


•

Сold or hot	


•

A monad
RACSignal *allPosts =
[RACSignal createSignal:^(id <RACSubscriber> s) {
[httpClient GET:@"/posts.json" success:^(NSArray *posts) {
[s sendNext:posts];
[s sendCompleted];
} failure:^(NSError *error) {
[s sendError:error];
}];

!

!

}];

return [RACDisposable disposableWithBlock:^{
[operation cancel];
}];

RACSignal *posts =
[[allPosts flattenMap:^(NSArray *items) {
return items.rac_signal;
}] filter:^(Post *post) {
return post.hasComments;
}];
// Nothing happened yet

!

[[posts collect] subscribeNext:^(NSArray *items) { NSLog(@"Posts: %@", items) }];

!

RACDisposable *disposable =
[posts subscribeCompleted:^{ NSLog(@"Done"); }];
// Ooops network request performed twice :(

!

[disposable dispose];
STREAMS
•

Powerful abstraction	


•

Streams for futures is like iterables for scalar values	


•

Umbrella concept for asynchronous Cocoa
patterns	


•

You can even use signals as values. Yo dawg…
RACSignal *searchResults =
[[[[textField.rac_textSignal throttle:1] filter:^(NSString *query) {
return query.length > 2;
}] map:^(NSString *query) {
return [[[networkClient itemsMatchingQuery:query]
doError:^(NSError *error) {
[self displayError:error];
}]
catchTo:[RACSignal empty]];
}] switchToLatest];

!

// Automatically disposes subscription on self deallocation
// cancelation running network request (if any)
RAC(self, items) = searchResults;
DEALING WITH IMPERATIVE
API
•

Property binding (one-way and two-way)	


•

Selector lifting (-rac_liftSelector:withSignals:)	


•

Signals from selector (-rac_signalForSelector:)	


•

Operators for injecting side-effects: doNext, doError,
initially, finally
RACSignal *range = [[[RACSignal merge:@[
[self rac_signalForSelector:@selector(tableView:willDisplayCell...)]
[self rac_signalForSelector:@selector(tableView:didEndDisplayingCell...)]
]] map:^(RACtuple *args) {
UITableView *tableView = args[0];
NSArray *indexPaths = tableView.indexPathsForVisibleRows;
NSRange range = NSMakeRange([indexPaths[0] row], indexPaths.count);
return [NSValue valueWithRange:range];
}];

!

[self rac_liftSelector:@selector(updateVisibleRange:)
withSignals:range, nil];
CONCURRENCY
•

RACScheduler

•

-deliverOn:

and -subscribeOn:

- (RACSignal *)itemsFromDB {
return [RACSignal createSignal:^(id <RACSubscriber> subscriber) {
NSArray *items = [sqliteWrapper fetchItemsFromTable:@"posts"];

!

[subscriber sendNext:items];
[subscriber sendCompleted];

!
}

!

}];

return nil;

[[[[self itemsFromDB]
subscribeOn:[RACScheduler scheduler]]
deliverOn:[RACScheduler mainThreadScheduler]]
subscribeNext:^(NSArray *items) {
self.items = items;
}];
ISSUES
•

Steep learning curve	


•

Runtime overhead	


•

Tricky debugging: crazy call stacks, lots of asynchrony,
retain cycles	


•

You’ll need to deal with imperative Cocoa API anyway	


•

Losing last bits of type information
MVVM
View

Model

View
Controller
MVVM
•

Model – View – View Model	


•

An alternative to MVC	


•

MVC is fine, but…	


•

Meet UIViewController, The Spaghetti Monster
Model

View
Model

View
MVVM
•

MVVM knows nothing about a view	


•

MVVM uses underlying layers (persistence, web
service clients, cache) to populate view data	


•

You can even use it with ncurses
WHY MVVM?
•

Clear separation between view and presentation logiс	


•

Reusability across different views and even platforms	


•

Testability	


•

View models are models	


•

Persistence can be hidden behind view model
YOU ALREADY CLOSER TO
MVVM THAN YOU THINK
Big monolithic view controllers	

!

External data sources, data converters & services	

!

MVVM
@interface UserRepositoryViewModel : NSObject

!

// KVOable properties
@property (nonatomic, copy, readonly) NSArray *items;
@property (nonatomic, strong, readonly) User *selectedUser;
@property (nonatomic, readonly) BOOL isLoading;

!

- (void)refreshItems;
- (void)selectItemAtIndex;

!

@end
MVVM + RAC
•

KVO with RACObserve	


•

One-way binding: RAC(object,

•

Two-way binding: RACChannel	


•

RACCommand

keyPath) = signal;
@interface LoginViewModel : NSObject

!

@property (nonatomic, copy) NSString *login;
@property (nonatomic, copy) NSString *password;

!

@property (nonatomic, strong, readonly) RACCommand *login;

!

@end

!
!

// Somewhere in view controller
id viewTerminal = loginField.rac_newTextChannel;
id modelTerminal = RACChannelTo(viewModel, login);

!

[[viewTerminal map:^(NSString *value) {
return [value lowercaseString];
}] subscribe:modelTerminal];
[modelTerminal subscribe:viewTerminal];

!

loginButton.rac_command = viewModel.login;
[self rac_liftSelector:@selector(displayError:)
withSignals:viewModel.login.errors, nil];

!

RAC(spinner, animating) = viewModel.login.executing;
RACCommand
•

Runs signal block on -execute: and subscribes to its result	


•

Multicasts execution signals to consumers	


•

Multicasts inner signal errors to consumers	


•

Enabled/disabled state can be controlled by a bool signal	


•

Exposes execution state (running/not running)	


•

Can be bound to UI control
RACSignal *networkReachable = RACObserve(httpClient, reachable);

!

RACCommand *login = [[RACCommand alloc]
initWithEnabled:networkReachable
signalBlock:^(id _) {
// Boolean signal, sends @YES on success
return [self.backendClient loginWithLogin:self.login
password:self.password];
}];

!

RAC(self, loggedIn) = [[login.executionSignals switchToLatest]
startWith:@NO];
•

Make no assumptions about a view	


•

Expose bindable properties or signals	


•

Expose commands to consumers	


•

Throttle/unsubscribe signals when view is
inactive
ANY QUESTIONS?
LINKS
•

https://github.com/ReactiveCocoa/ReactiveCocoa/	


•

https://github.com/ReactiveCocoa/ReactiveViewModel	


•

http://cocoamanifest.net/articles/2013/10/mvc-mvvm-frpand-building-bridges.html	


•

https://rx.codeplex.com	


•

http://netflix.github.io/RxJava/javadoc/rx/Observable.html
RAC-POWERED LIBRARIES
•

https://github.com/octokit/octokit.objc	


•

https://github.com/jonsterling/ReactiveFormlets	


•

https://github.com/ReactiveCocoa/
ReactiveCocoaLayout
SAMPLE PROJECTS
•

https://github.com/AshFurrow/C-41	


•

https://github.com/jspahrsummers/GroceryList/	


•

https://github.com/corristo/SoundCloudStream

More Related Content

PDF
Встреча №9. Будущее паттерна MVVM в iOS приложениях, Денис Лебедев
PDF
Workshop 16: EmberJS Parte I
PDF
Workshop 9: BackboneJS y patrones MVC
PDF
SpringMVC
PPTX
Single Page Applications with AngularJS 2.0
PDF
Web sockets in Angular
PDF
Overview of the AngularJS framework
ODP
Angularjs
Встреча №9. Будущее паттерна MVVM в iOS приложениях, Денис Лебедев
Workshop 16: EmberJS Parte I
Workshop 9: BackboneJS y patrones MVC
SpringMVC
Single Page Applications with AngularJS 2.0
Web sockets in Angular
Overview of the AngularJS framework
Angularjs

What's hot (20)

PDF
AngularJS with RequireJS
PPTX
Angular 1.x in action now
PPTX
Introduction to Angularjs
PPTX
Migrating an application from Angular 1 to Angular 2
PDF
Angular2 Development for Java developers
PDF
Break the monolith with (B)VIPER Modules
PDF
From Swing to JavaFX
PDF
How AngularJS Embraced Traditional Design Patterns
PDF
Speed up your Web applications with HTML5 WebSockets
PPTX
Sexy Architecting. VIPER: MVP on steroids
PDF
Reactive Streams and RxJava2
PPTX
Angular Lazy Loading and Resolve (Route Resolver)
PPTX
ASp.net Mvc 5
PPT
JavaScript
PDF
Exploring Angular 2 - Episode 1
PDF
Spring MVC Intro / Gore - Nov NHJUG
PDF
Dart for Java Developers
PPTX
Front end development with Angular JS
PDF
Dependency Injection @ AngularJS
AngularJS with RequireJS
Angular 1.x in action now
Introduction to Angularjs
Migrating an application from Angular 1 to Angular 2
Angular2 Development for Java developers
Break the monolith with (B)VIPER Modules
From Swing to JavaFX
How AngularJS Embraced Traditional Design Patterns
Speed up your Web applications with HTML5 WebSockets
Sexy Architecting. VIPER: MVP on steroids
Reactive Streams and RxJava2
Angular Lazy Loading and Resolve (Route Resolver)
ASp.net Mvc 5
JavaScript
Exploring Angular 2 - Episode 1
Spring MVC Intro / Gore - Nov NHJUG
Dart for Java Developers
Front end development with Angular JS
Dependency Injection @ AngularJS
Ad

Viewers also liked (10)

PDF
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
PPTX
ReactiveCocoa: делаем отзывчивое приложение (П. Руденко)
PDF
Rambler.iOS #5: VIPER a la Rambler
PPTX
[SIP 2015] iOS Proposal: VIPER
PPTX
Viper - чистая архитектура iOS-приложения (И. Чирков)
PDF
Introduction to VIPER Architecture
PDF
From mvc to viper
PDF
iOS viper presentation
PPTX
VIPER - Design Pattern
PDF
Rambler.iOS #5: VIPER и Swift
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
ReactiveCocoa: делаем отзывчивое приложение (П. Руденко)
Rambler.iOS #5: VIPER a la Rambler
[SIP 2015] iOS Proposal: VIPER
Viper - чистая архитектура iOS-приложения (И. Чирков)
Introduction to VIPER Architecture
From mvc to viper
iOS viper presentation
VIPER - Design Pattern
Rambler.iOS #5: VIPER и Swift
Ad

Similar to «ReactiveCocoa и MVVM» — Николай Касьянов, SoftWear (20)

PDF
ReactiveCocoa Goodness - Part I of II
PDF
Reactive cocoa cocoaheadsbe_2014
PDF
Reactive Cocoa
PDF
Learn You a ReactiveCocoa for Great Good
PDF
Reactive cocoa
PDF
ReactiveCocoa in Practice
PDF
Introduction to reactive programming & ReactiveCocoa
PDF
MVVM & RxSwift
PDF
An Introduction to Reactive Cocoa
PDF
Functional Reactive Programming (CocoaHeads Bratislava)
PDF
Intro to ReactiveCocoa
PDF
Models used in iOS programming, with a focus on MVVM
PPT
Reactive cocoa
PDF
MV(C, mvvm) in iOS and ReactiveCocoa
PDF
Hello, ReactorKit 
PPT
Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"
PPT
iOS Multithreading
PDF
Reactive Cocoa Lightning Talk
PDF
iOS 2 - The practical Stuff
PDF
Reactive cocoa made Simple with Swift
ReactiveCocoa Goodness - Part I of II
Reactive cocoa cocoaheadsbe_2014
Reactive Cocoa
Learn You a ReactiveCocoa for Great Good
Reactive cocoa
ReactiveCocoa in Practice
Introduction to reactive programming & ReactiveCocoa
MVVM & RxSwift
An Introduction to Reactive Cocoa
Functional Reactive Programming (CocoaHeads Bratislava)
Intro to ReactiveCocoa
Models used in iOS programming, with a focus on MVVM
Reactive cocoa
MV(C, mvvm) in iOS and ReactiveCocoa
Hello, ReactorKit 
Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"
iOS Multithreading
Reactive Cocoa Lightning Talk
iOS 2 - The practical Stuff
Reactive cocoa made Simple with Swift

More from e-Legion (20)

PPTX
MBLT16: Elena Rydkina, Pure
PPTX
MBLT16: Alexander Lukin, AppMetrica
PPTX
MBLT16: Vincent Wu, Alibaba Mobile
PPTX
MBLT16: Dmitriy Geranin, Afisha Restorany
PPTX
MBLT16: Marvin Liao, 500Startups
PDF
MBLT16: Andrey Maslak, Aviasales
PDF
MBLT16: Andrey Bakalenko, Sberbank Online
PPTX
Rx Java architecture
PPTX
Rx java
PDF
MBLTDev15: Hector Zarate, Spotify
PDF
MBLTDev15: Cesar Valiente, Wunderlist
PDF
MBLTDev15: Brigit Lyons, Soundcloud
PDF
MBLTDev15: Egor Tolstoy, Rambler&Co
PDF
MBLTDev15: Alexander Orlov, Postforpost
PDF
MBLTDev15: Artemiy Sobolev, Parallels
PPTX
MBLTDev15: Alexander Dimchenko, DIT
PPTX
MBLTDev: Evgeny Lisovsky, Litres
PPTX
MBLTDev: Alexander Dimchenko, Bright Box
PPTX
MBLTDev15: Konstantin Goldshtein, Microsoft
PDF
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLT16: Elena Rydkina, Pure
MBLT16: Alexander Lukin, AppMetrica
MBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Marvin Liao, 500Startups
MBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Bakalenko, Sberbank Online
Rx Java architecture
Rx java
MBLTDev15: Hector Zarate, Spotify
MBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Alexander Dimchenko, DIT
MBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank

«ReactiveCocoa и MVVM» — Николай Касьянов, SoftWear