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
既存デザインを変更せずにタップ領域を広げる方法
tahia910
1
270
XP, Testing and ninja testing
m_seki
3
220
生成AIコーディングとの向き合い方、AIと共創するという考え方 / How to deal with generative AI coding and the concept of co-creating with AI
seike460
PRO
1
350
#QiitaBash MCPのセキュリティ
ryosukedtomita
0
830
Porting a visionOS App to Android XR
akkeylab
0
190
0626 Findy Product Manager LT Night_高田スライド_speaker deck用
mana_takada
0
140
PHP 8.4の新機能「プロパティフック」から学ぶオブジェクト指向設計とリスコフの置換原則
kentaroutakeda
2
720
dbt民主化とLLMによる開発ブースト ~ AI Readyな分析サイクルを目指して ~
yoshyum
3
300
VS Code Update for GitHub Copilot
74th
2
590
Code as Context 〜 1にコードで 2にリンタ 34がなくて 5にルール? 〜
yodakeisuke
0
120
「Cursor/Devin全社導入の理想と現実」のその後
saitoryc
0
700
スタートアップの急成長を支えるプラットフォームエンジニアリングと組織戦略
sutochin26
0
330
Featured
See All Featured
Building an army of robots
kneath
306
45k
Java REST API Framework Comparison - PWX 2021
mraible
31
8.7k
Writing Fast Ruby
sferik
628
62k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.6k
Practical Orchestrator
shlominoach
188
11k
Making Projects Easy
brettharned
116
6.3k
Building Applications with DynamoDB
mza
95
6.5k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
252
21k
Designing Experiences People Love
moore
142
24k
Site-Speed That Sticks
csswizardry
10
680
For a Future-Friendly Web
brad_frost
179
9.8k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
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