Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Colin Eberhardt | ReactiveCocoa and Swift: Bett...
Search
Swift Summit
March 21, 2015
Programming
3
14k
Colin Eberhardt | ReactiveCocoa and Swift: Better Together
Presented at
www.swiftsummit.com
Swift Summit
March 21, 2015
Tweet
Share
More Decks by Swift Summit
See All by Swift Summit
Jack Nutting | let swift = Race?
swiftsummit
1
2.7k
Marcin Krzyżanowski | CryptoSwift: Crypto You Can Do
swiftsummit
0
25k
Radek Pietruszewski | Swifty Methods
swiftsummit
2
7.6k
Gem Barrett | View from the Other Side
swiftsummit
0
1.5k
Joseph Lord | How Swift is Swift?
swiftsummit
2
31k
Al Skipp | The Monad Among Us
swiftsummit
3
800
Al Skipp | The Monad Among Us
swiftsummit
1
4.1k
Brian Gesiak | Swift API Design: Getting Results
swiftsummit
0
7.3k
Anthony Levings | JSON, Swift and Type Safety: It's a wrap
swiftsummit
2
19k
Other Decks in Programming
See All in Programming
PyCon mini 東海 2025「個人ではじめるマルチAIエージェント入門 〜LangChain × LangGraphでアイデアを形にするステップ〜」
komofr
3
920
AI POSにおけるLLM Observability基盤の導入 ― サイバーエージェントDXインターン成果報告
hekuchan
0
480
なぜ強調表示できず ** が表示されるのか — Perlで始まったMarkdownの歴史と日本語文書における課題
kwahiro
9
5.1k
PHPライセンス変更の議論を通じて学ぶOSSライセンスの基礎
matsuo_atsushi
0
140
AI駆動開発ライフサイクル(AI-DLC)のホワイトペーパーを解説
swxhariu5
0
510
Register is more than clipboard
satorunooshie
1
460
組織もソフトウェアも難しく考えない、もっとシンプルな考え方で設計する #phpconfuk
o0h
PRO
10
4k
Private APIの呼び出し方
kishikawakatsumi
2
830
Atomics APIを知る / Understanding Atomics API
ssssota
1
120
問題の見方を変える「システム思考」超入門
panda_program
0
190
CSC509 Lecture 11
javiergs
PRO
0
300
Vueで学ぶデータ構造入門 リンクリストとキューでリアクティビティを捉える / Vue Data Structures: Linked Lists and Queues for Reactivity
konkarin
1
180
Featured
See All Featured
Learning to Love Humans: Emotional Interface Design
aarron
274
41k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.8k
Typedesign – Prime Four
hannesfritz
42
2.9k
How STYLIGHT went responsive
nonsquared
100
5.9k
Designing Experiences People Love
moore
142
24k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Writing Fast Ruby
sferik
630
62k
The Invisible Side of Design
smashingmag
302
51k
The Language of Interfaces
destraynor
162
25k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
658
61k
Transcript
ReactiveCocoa and Swift Better Together @ColinEberhardt ShinobiControls
None
None
[[[[[[[[[[[[
f*****gblocksyntax.com
ReactiveCocoa In ten minutes
Functional Reactive Programming Functional Programming Reactive Programming + =
ReactiveCocoa In my own words
Every line of code we write is executed in reaction
to an event
But … these events come in many different forms
ReactiveCocoa provides a common interface for all events
… this allows us to define a language for manipulating,
transforming and coordinating events
ReactiveCocoa in action
RACSignal *textSignal = [self.usernameTextField rac_textSignal]; [textSignal subscribeNext:^(id x) { NSLog(x);
}];
None
Signals emit events to their subscribers
… they emit none, one or more next events, optionally
followed by either an error or completed NEXT NEXT NEXT NEXT … NEXT NEXT ERROR COMPLETED
Signal All Things!
RACSignal *textSignal = [self.usernameTextField rac_textSignal]; RACSignal *filteredText = [textSignal filter:^BOOL(NSString
*text) { return text.length > 3; }]; [filteredText subscribeNext:^(id x) { NSLog(x); }];
None
What are events? and what do they look like?
anything!
RACSignal *textSignal = [self.usernameTextField rac_textSignal]; RACSignal *textLength = [textSignal map:^id(NSString
*text) { return @(text.length); }]; [textLength subscribeNext:^(id x) { NSLog(@"%@", x); }];
None
RACSignal *textSignal = [self.usernameTextField rac_textSignal]; RACSignal *textLength = [textSignal map:^id(NSString
*text) { return @(text.length); }]; RACSignal *filteredText = [textLength filter:^BOOL(NSNumber *length) { return [length intValue] > 3; }]; [filteredText subscribeNext:^(id x) { NSLog(@"%@", x); }];
[[[[self.usernameTextField rac_textSignal] map:^id(NSString *text) { return @(text.length); }] filter:^BOOL(NSNumber *length)
{ return [length intValue] > 3; }] subscribeNext:^(id x) { NSLog(@"%@", x); }];
rac_textSIgnal- filter- subscribeNext- Value->-3- map- NSString- NSNumber-
rac_textSignal- filter- setKeyPath- thro5le- filter- fla5enMap- twi5erSearch- deliverOn- subscribeNext- requestAccess-
signal- then-
[[[[[[[[self requestAccessToTwitterSignal] then:^RACSignal *{ @strongify(self) return self.searchText.rac_textSignal; }] filter:^BOOL(NSString *text)
{ @strongify(self) return [self isValidSearchText:text]; }] throttle:0.5] flattenMap:^RACStream *(NSString *text) { @strongify(self) return [self signalForSearchWithText:text]; }] map:^id(NSDictionary *jsonSearchResult) { NSArray *statuses = jsonSearchResult[@"statuses"]; NSArray *tweets = [statuses linq_select:^id(id tweet) { return [RWTweet tweetWithStatus:tweet]; }]; return tweets; }] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSArray *tweets) { [self.resultsViewController displayTweets:tweets]; } error:^(NSError *error) { NSLog(@"An error occurred: %@", error); }];
None
None
None
ReactiveCocoa Swift
[[[[[[[[self requestAccessToTwitterSignal] then:^RACSignal *{ @strongify(self) return self.searchText.rac_textSignal; }] filter:^BOOL(NSString *text)
{ @strongify(self) return [self isValidSearchText:text]; }] throttle:0.5] flattenMap:^RACStream *(NSString *text) { @strongify(self) return [self signalForSearchWithText:text]; }] map:^id(NSDictionary *jsonSearchResult) { NSArray *statuses = jsonSearchResult[@"statuses"]; NSArray *tweets = [statuses linq_select:^id(id tweet) { return [RWTweet tweetWithStatus:tweet]; }]; return tweets; }] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSArray *tweets) { [self.resultsViewController displayTweets:tweets]; } error:^(NSError *error) { NSLog(@"An error occurred: %@", error); }];
[[[[[[[[[[[[
requestAccessToTwitterSignal() .then { self.searchTextField.rac_textSignal() } .filterAs { (text: NSString) ->
Bool in text.length > 3 } .doNext { (any) in self.tweetsTableView.alpha = 0.5 } .throttle(0.5) .flattenMapAs { (text: NSString) -> RACStream in self.signalForSearchWithText(text) } .deliverOn(RACScheduler.mainThreadScheduler()) .subscribeNextAs ({ (tweets: NSDictionary) in let statuses = tweets["statuses"] as [NSDictionary] self.tweets = statuses.map { Tweet(json: $0) } self.tweetsTableView.reloadData() self.tweetsTableView.scrollToTop() self.tweetsTableView.alpha = 1.0 }, { (error) in println(error) })
requestAccessToTwitterSignal() .then { self.searchTextField.rac_textSignal() } .filterAs { (text: NSString) ->
Bool in text.length > 3 } .doNext { (any) in self.tweetsTableView.alpha = 0.5 } .throttle(0.5) .flattenMapAs { (text: NSString) -> RACStream in self.signalForSearchWithText(text) } .deliverOn(RACScheduler.mainThreadScheduler()) .subscribeNextAs ({ (tweets: NSDictionary) in let statuses = tweets["statuses"] as [NSDictionary] self.tweets = statuses.map { Tweet(json: $0) } self.tweetsTableView.reloadData() self.tweetsTableView.scrollToTop() self.tweetsTableView.alpha = 1.0 }, { (error) in println(error) })
Swift ReactiveCocoa
Swift encourages immutability
51 variables
39 constants 12 variables 6 outlets (not my fault!) 1
UIWindow 5 UI state variables
ReactiveCocoa 3
public final class Signal<T, E: ErrorType> { ... }
requestAccessToTwitterSignal() .then { self.searchTextField.rac_textSignal() } .filterAs { (text: NSString) ->
Bool in text.length > 3 } .doNext { (any) in self.tweetsTableView.alpha = 0.5 } .throttle(0.5) .flattenMapAs { (text: NSString) -> RACStream in self.signalForSearchWithText(text) } .deliverOn(RACScheduler.mainThreadScheduler()) .subscribeNextAs ({ (tweets: NSDictionary) in let statuses = tweets["statuses"] as [NSDictionary] self.tweets = statuses.map { Tweet(json: $0) } self.tweetsTableView.reloadData() self.tweetsTableView.scrollToTop() self.tweetsTableView.alpha = 1.0 }, { (error) in println(error) })
requestAccessToTwitterSignal() |> then (textField.rac3_textSignal()) |> filter { countElements($0) > 3
} |> throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler) |> doNext { text in self.tweetsTableView.alpha = 0.5 } |> flattenMap { self.signalForSearchWithText($0) } |> observeOn(QueueScheduler.mainQueueScheduler) |> observe(next: { tweetsDictionary in let statuses = tweetsDictionary["statuses"] as [NSDictionary] self.tweets = statuses.map { Tweet(json: $0) } self.tweetsTableView.reloadData() self.tweetsTableView.alpha = 1.0 })
pipe forward operator |>
public final class Signal<T, E: ErrorType> { func map (…)
-> Signal }
public final class Signal<T, E: ErrorType> { } func map
(…) -> Signal
let mapped = map(signal, { $0.foo })
let mapped = map(map(signal, { $0.foo }), { $0.bar })
let mapped = map(map(map(signal, { $0.foo }), { $0.bar }),
{ $0.sadface })
func map<T, U, E>(transform: T -> U) (signal: Signal<T, E>)
-> Signal<U, E>
public func |> <T, E, X> (signal: Signal<T, E>, transform:
Signal<T, E> -> X) -> X { return transform(signal) }
None
func |><X> (stringy: Stringy, transform: Stringy -> X) -> X
{ return transform(stringy) }
func } |><X>
ReactiveCocoa Swift ReactiveCocoa http://tiny.cc/reactive-swift