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
780
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
KMP와 kotlinx.rpc로 서버와 클라이언트 동기화
kwakeuijin
0
300
Stackless и stackful? Корутины и асинхронность в Go
lamodatech
0
1.3k
いりゃあせ、PHPカンファレンス名古屋2025 / Welcome to PHP Conference Nagoya 2025
ttskch
1
180
ATDDで素早く安定した デリバリを実現しよう!
tonnsama
1
1.9k
Lookerは可視化だけじゃない。UIコンポーネントもあるんだ!
ymd65536
1
130
GitHub CopilotでTypeScriptの コード生成するワザップ
starfish719
26
6k
20241217 競争力強化とビジネス価値創出への挑戦:モノタロウのシステムモダナイズ、開発組織の進化と今後の展望
monotaro
PRO
0
290
ドメインイベント増えすぎ問題
h0r15h0
2
570
BEエンジニアがFEの業務をできるようになるまでにやったこと
yoshida_ryushin
0
200
ErdMap: Thinking about a map for Rails applications
makicamel
1
650
アクターシステムに頼らずEvent Sourcingする方法について
j5ik2o
6
700
Rubyでつくるパケットキャプチャツール
ydah
0
170
Featured
See All Featured
Practical Orchestrator
shlominoach
186
10k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
45
2.3k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
Building Adaptive Systems
keathley
38
2.4k
BBQ
matthewcrist
85
9.4k
Designing on Purpose - Digital PM Summit 2013
jponch
116
7.1k
Scaling GitHub
holman
459
140k
Building a Scalable Design System with Sketch
lauravandoore
460
33k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.8k
Statistics for Hackers
jakevdp
797
220k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.6k
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