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
自作OSでDOOMを動かしてみた
zakki0925224
1
1.4k
Oracle Database Technology Night 92 Database Connection control FAN-AC
oracle4engineer
PRO
1
220
パスタの技術
yusukebe
1
400
RDoc meets YARD
okuramasafumi
2
130
DockerからECSへ 〜 AWSの海に出る前に知っておきたいこと 〜
ota1022
5
1.8k
Nuances on Kubernetes - RubyConf Taiwan 2025
envek
0
200
技術的負債で信頼性が限界だったWordPress運用をShifterで完全復活させた話
rvirus0817
1
2.1k
未来を拓くAI技術〜エージェント開発とAI駆動開発〜
leveragestech
2
180
Infer入門
riru
4
1.6k
Langfuseと歩む生成AI活用推進
licux
3
300
書き捨てではなく継続開発可能なコードをAIコーディングエージェントで書くために意識していること
shuyakinjo
1
310
モバイルアプリからWebへの横展開を加速した話_Claude_Code_実践術.pdf
kazuyasakamoto
0
270
Featured
See All Featured
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
9
780
Rails Girls Zürich Keynote
gr2m
95
14k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
8
480
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.4k
Optimising Largest Contentful Paint
csswizardry
37
3.4k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
50
5.5k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.5k
How to Think Like a Performance Engineer
csswizardry
25
1.8k
Art, The Web, and Tiny UX
lynnandtonic
302
21k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.4k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
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