SlideShare une entreprise Scribd logo
1  sur  30
Télécharger pour lire hors ligne
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

Contenu connexe

Tendances

AngularJS with RequireJS
AngularJS with RequireJSAngularJS with RequireJS
AngularJS with RequireJSJohannes Weber
 
Angular 1.x in action now
Angular 1.x in action nowAngular 1.x in action now
Angular 1.x in action nowGDG Odessa
 
Migrating an application from Angular 1 to Angular 2
Migrating an application from Angular 1 to Angular 2 Migrating an application from Angular 1 to Angular 2
Migrating an application from Angular 1 to Angular 2 Ross Dederer
 
Angular2 Development for Java developers
Angular2 Development for Java developersAngular2 Development for Java developers
Angular2 Development for Java developersYakov Fain
 
Break the monolith with (B)VIPER Modules
Break the monolith with (B)VIPER ModulesBreak the monolith with (B)VIPER Modules
Break the monolith with (B)VIPER ModulesNicola Zaghini
 
How AngularJS Embraced Traditional Design Patterns
How AngularJS Embraced Traditional Design PatternsHow AngularJS Embraced Traditional Design Patterns
How AngularJS Embraced Traditional Design PatternsRan Mizrahi
 
Speed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsSpeed up your Web applications with HTML5 WebSockets
Speed up your Web applications with HTML5 WebSocketsYakov Fain
 
Sexy Architecting. VIPER: MVP on steroids
Sexy Architecting. VIPER: MVP on steroidsSexy Architecting. VIPER: MVP on steroids
Sexy Architecting. VIPER: MVP on steroidsDmytro Zaitsev
 
Reactive Streams and RxJava2
Reactive Streams and RxJava2Reactive Streams and RxJava2
Reactive Streams and RxJava2Yakov Fain
 
Angular Lazy Loading and Resolve (Route Resolver)
Angular Lazy Loading and Resolve (Route Resolver)Angular Lazy Loading and Resolve (Route Resolver)
Angular Lazy Loading and Resolve (Route Resolver)Squash Apps Pvt Ltd
 
Exploring Angular 2 - Episode 1
Exploring Angular 2 - Episode 1Exploring Angular 2 - Episode 1
Exploring Angular 2 - Episode 1Ahmed Moawad
 
Spring MVC Intro / Gore - Nov NHJUG
Spring MVC Intro / Gore - Nov NHJUGSpring MVC Intro / Gore - Nov NHJUG
Spring MVC Intro / Gore - Nov NHJUGTed Pennings
 
Dart for Java Developers
Dart for Java DevelopersDart for Java Developers
Dart for Java DevelopersYakov Fain
 
Front end development with Angular JS
Front end development with Angular JSFront end development with Angular JS
Front end development with Angular JSBipin
 
Dependency Injection @ AngularJS
Dependency Injection @ AngularJSDependency Injection @ AngularJS
Dependency Injection @ AngularJSRan Mizrahi
 

Tendances (20)

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

En vedette

Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPERRambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPER
Rambler.iOS #5: Генерамба и прочие аспекты кодогенерации в VIPERRAMBLER&Co
 
ReactiveCocoa: делаем отзывчивое приложение (П. Руденко)
ReactiveCocoa: делаем отзывчивое приложение (П. Руденко)ReactiveCocoa: делаем отзывчивое приложение (П. Руденко)
ReactiveCocoa: делаем отзывчивое приложение (П. Руденко)65apps
 
Rambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la RamblerRambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la RamblerRAMBLER&Co
 
[SIP 2015] iOS Proposal: VIPER
[SIP 2015] iOS Proposal: VIPER[SIP 2015] iOS Proposal: VIPER
[SIP 2015] iOS Proposal: VIPERSilicon Straits
 
Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)Viper - чистая архитектура iOS-приложения (И. Чирков)
Viper - чистая архитектура iOS-приложения (И. Чирков)65apps
 
Introduction to VIPER Architecture
Introduction to VIPER ArchitectureIntroduction to VIPER Architecture
Introduction to VIPER ArchitectureHendy Christianto
 
iOS viper presentation
iOS viper presentationiOS viper presentation
iOS viper presentationRajat Datta
 
Rambler.iOS #5: VIPER и Swift
Rambler.iOS #5: VIPER и SwiftRambler.iOS #5: VIPER и Swift
Rambler.iOS #5: VIPER и SwiftRAMBLER&Co
 

En vedette (10)

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

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

Functional Reactive Programming (CocoaHeads Bratislava)
Functional Reactive Programming (CocoaHeads Bratislava)Functional Reactive Programming (CocoaHeads Bratislava)
Functional Reactive Programming (CocoaHeads Bratislava)Michal Grman
 
Adding Riak to your NoSQL Bag of Tricks
Adding Riak to your NoSQL Bag of TricksAdding Riak to your NoSQL Bag of Tricks
Adding Riak to your NoSQL Bag of Trickssiculars
 
Blocks & GCD
Blocks & GCDBlocks & GCD
Blocks & GCDrsebbe
 
Riak at The NYC Cloud Computing Meetup Group
Riak at The NYC Cloud Computing Meetup GroupRiak at The NYC Cloud Computing Meetup Group
Riak at The NYC Cloud Computing Meetup Groupsiculars
 
(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of us(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of usStefan Adolf
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffJAX London
 
Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"
Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"
Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"Lviv Startup Club
 
Medium TechTalk — iOS
Medium TechTalk — iOSMedium TechTalk — iOS
Medium TechTalk — iOSjimmyatmedium
 
Intro to ReactiveCocoa
Intro to ReactiveCocoaIntro to ReactiveCocoa
Intro to ReactiveCocoakleneau
 
Scarlet SmallTalk
Scarlet SmallTalkScarlet SmallTalk
Scarlet SmallTalkESUG
 
MSc Enterprise Systems Development Guest Lecture at UniS (2/12/09)
MSc Enterprise Systems Development Guest Lecture at UniS (2/12/09)MSc Enterprise Systems Development Guest Lecture at UniS (2/12/09)
MSc Enterprise Systems Development Guest Lecture at UniS (2/12/09)Daniel Bryant
 
Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Ran Mizrahi
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Ran Mizrahi
 
Project kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scalaProject kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scalaSkills Matter Talks
 
Android MvRx Framework 介紹
Android MvRx Framework 介紹Android MvRx Framework 介紹
Android MvRx Framework 介紹Kros Huang
 
Play Framework and Activator
Play Framework and ActivatorPlay Framework and Activator
Play Framework and ActivatorKevin Webber
 

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

Reactive cocoa
Reactive cocoaReactive cocoa
Reactive cocoa
 
Functional Reactive Programming (CocoaHeads Bratislava)
Functional Reactive Programming (CocoaHeads Bratislava)Functional Reactive Programming (CocoaHeads Bratislava)
Functional Reactive Programming (CocoaHeads Bratislava)
 
Adding Riak to your NoSQL Bag of Tricks
Adding Riak to your NoSQL Bag of TricksAdding Riak to your NoSQL Bag of Tricks
Adding Riak to your NoSQL Bag of Tricks
 
Couchbas for dummies
Couchbas for dummiesCouchbas for dummies
Couchbas for dummies
 
Blocks & GCD
Blocks & GCDBlocks & GCD
Blocks & GCD
 
Riak at The NYC Cloud Computing Meetup Group
Riak at The NYC Cloud Computing Meetup GroupRiak at The NYC Cloud Computing Meetup Group
Riak at The NYC Cloud Computing Meetup Group
 
(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of us(2018) Webpack Encore - Asset Management for the rest of us
(2018) Webpack Encore - Asset Management for the rest of us
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
 
Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"
Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"
Lviv MD Day 2015 Павло Захаров "Reactive cocoa: paradigm shift"
 
Medium TechTalk — iOS
Medium TechTalk — iOSMedium TechTalk — iOS
Medium TechTalk — iOS
 
Scala and Spring
Scala and SpringScala and Spring
Scala and Spring
 
Intro to ReactiveCocoa
Intro to ReactiveCocoaIntro to ReactiveCocoa
Intro to ReactiveCocoa
 
Scarlet SmallTalk
Scarlet SmallTalkScarlet SmallTalk
Scarlet SmallTalk
 
MSc Enterprise Systems Development Guest Lecture at UniS (2/12/09)
MSc Enterprise Systems Development Guest Lecture at UniS (2/12/09)MSc Enterprise Systems Development Guest Lecture at UniS (2/12/09)
MSc Enterprise Systems Development Guest Lecture at UniS (2/12/09)
 
Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)
 
Project kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scalaProject kepler compile time metaprogramming for scala
Project kepler compile time metaprogramming for scala
 
Android MvRx Framework 介紹
Android MvRx Framework 介紹Android MvRx Framework 介紹
Android MvRx Framework 介紹
 
Rack
RackRack
Rack
 
Play Framework and Activator
Play Framework and ActivatorPlay Framework and Activator
Play Framework and Activator
 

Plus de e-Legion

MBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, PureMBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, Puree-Legion
 
MBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetricaMBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetricae-Legion
 
MBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba MobileMBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba Mobilee-Legion
 
MBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha RestoranyMBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha Restoranye-Legion
 
MBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500StartupsMBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500Startupse-Legion
 
MBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, AviasalesMBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, Aviasalese-Legion
 
MBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank OnlineMBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank Onlinee-Legion
 
Rx Java architecture
Rx Java architectureRx Java architecture
Rx Java architecturee-Legion
 
MBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, SpotifyMBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, Spotifye-Legion
 
MBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, WunderlistMBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, Wunderliste-Legion
 
MBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, SoundcloudMBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, Soundcloude-Legion
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Coe-Legion
 
MBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, PostforpostMBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, Postforposte-Legion
 
MBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, ParallelsMBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, Parallelse-Legion
 
MBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DITMBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DITe-Legion
 
MBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, LitresMBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, Litrese-Legion
 
MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box e-Legion
 
MBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, MicrosoftMBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, Microsofte-Legion
 
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank e-Legion
 

Plus de e-Legion (20)

MBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, PureMBLT16: Elena Rydkina, Pure
MBLT16: Elena Rydkina, Pure
 
MBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetricaMBLT16: Alexander Lukin, AppMetrica
MBLT16: Alexander Lukin, AppMetrica
 
MBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba MobileMBLT16: Vincent Wu, Alibaba Mobile
MBLT16: Vincent Wu, Alibaba Mobile
 
MBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha RestoranyMBLT16: Dmitriy Geranin, Afisha Restorany
MBLT16: Dmitriy Geranin, Afisha Restorany
 
MBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500StartupsMBLT16: Marvin Liao, 500Startups
MBLT16: Marvin Liao, 500Startups
 
MBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, AviasalesMBLT16: Andrey Maslak, Aviasales
MBLT16: Andrey Maslak, Aviasales
 
MBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank OnlineMBLT16: Andrey Bakalenko, Sberbank Online
MBLT16: Andrey Bakalenko, Sberbank Online
 
Rx Java architecture
Rx Java architectureRx Java architecture
Rx Java architecture
 
Rx java
Rx javaRx java
Rx java
 
MBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, SpotifyMBLTDev15: Hector Zarate, Spotify
MBLTDev15: Hector Zarate, Spotify
 
MBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, WunderlistMBLTDev15: Cesar Valiente, Wunderlist
MBLTDev15: Cesar Valiente, Wunderlist
 
MBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, SoundcloudMBLTDev15: Brigit Lyons, Soundcloud
MBLTDev15: Brigit Lyons, Soundcloud
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Co
 
MBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, PostforpostMBLTDev15: Alexander Orlov, Postforpost
MBLTDev15: Alexander Orlov, Postforpost
 
MBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, ParallelsMBLTDev15: Artemiy Sobolev, Parallels
MBLTDev15: Artemiy Sobolev, Parallels
 
MBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DITMBLTDev15: Alexander Dimchenko, DIT
MBLTDev15: Alexander Dimchenko, DIT
 
MBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, LitresMBLTDev: Evgeny Lisovsky, Litres
MBLTDev: Evgeny Lisovsky, Litres
 
MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box MBLTDev: Alexander Dimchenko, Bright Box
MBLTDev: Alexander Dimchenko, Bright Box
 
MBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, MicrosoftMBLTDev15: Konstantin Goldshtein, Microsoft
MBLTDev15: Konstantin Goldshtein, Microsoft
 
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
MBLTDev15: Anna Mikhina, Maxim Evdokimov, Tinkoff Bank
 

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

  • 1. REACTIVE COCOA & MVVM Николай Касьянов
  • 2. 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
  • 3. 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]; !
  • 4. 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
  • 5. 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];
  • 6. 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
  • 7. 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];
  • 8. 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…
  • 9. 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;
  • 10. 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
  • 11. 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];
  • 12. 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; }];
  • 13. 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
  • 14. MVVM
  • 16. MVVM • Model – View – View Model • An alternative to MVC • MVC is fine, but… • Meet UIViewController, The Spaghetti Monster
  • 18. 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
  • 19. 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
  • 20. YOU ALREADY CLOSER TO MVVM THAN YOU THINK Big monolithic view controllers ! External data sources, data converters & services ! MVVM
  • 21. @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
  • 22. MVVM + RAC • KVO with RACObserve • One-way binding: RAC(object, • Two-way binding: RACChannel • RACCommand keyPath) = signal;
  • 23. @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;
  • 24. 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
  • 25. 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];
  • 26. • Make no assumptions about a view • Expose bindable properties or signals • Expose commands to consumers • Throttle/unsubscribe signals when view is inactive