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
例外処理とどう使い分ける?Result型を使ったエラー設計 #burikaigi
kajitack
16
4.8k
GoLab2025 Recap
kuro_kurorrr
0
2.7k
gunshi
kazupon
1
140
チームをチームにするEM
hitode909
0
440
JETLS.jl ─ A New Language Server for Julia
abap34
2
470
Findy AI+の開発、運用におけるMCP活用事例
starfish719
0
2.1k
実は歴史的なアップデートだと思う AWS Interconnect - multicloud
maroon1st
0
310
[AI Engineering Summit Tokyo 2025] LLMは計画業務のゲームチェンジャーか? 最適化業務における活⽤の可能性と限界
terryu16
2
260
フロントエンド開発の勘所 -複数事業を経験して見えた判断軸の違い-
heimusu
6
1.9k
CSC307 Lecture 04
javiergs
PRO
0
620
LLM Çağında Backend Olmak: 10 Milyon Prompt'u Milisaniyede Sorgulamak
selcukusta
0
140
Vibe codingでおすすめの言語と開発手法
uyuki234
0
160
Featured
See All Featured
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
61k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.1k
We Have a Design System, Now What?
morganepeng
54
8k
Faster Mobile Websites
deanohume
310
31k
So, you think you're a good person
axbom
PRO
0
1.9k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
1.5k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.3k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
61
A better future with KSS
kneath
240
18k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.8k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
1
100
Practical Orchestrator
shlominoach
190
11k
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