SlideShare une entreprise Scribd logo
1  sur  66
Télécharger pour lire hors ligne
ReactiveCocoa and Swift 
Better Together 
@ColinEberhardt 
ShinobiControls
www.shinobicontrols.com
What is 
ReactiveCocoa?
Functional Programming 
+ 
Reactive Programming 
= 
Functional 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 
KVO 
delegates 
NSNotification 
target-action 
callbacks
ReactiveCocoa provides a 
common interface for all events!
… this allows us to define a 
language for manipulating, 
transforming and coordinating 
events
ReactiveCocoa 
Made Simple
Get Reactive 
let textSignal: RACSignal = 
usernameTextField.rac_textSignal() 
textSignal.subscribeNext { 
(text: AnyObject!) -> Void in 
let textString = text as String 
println(textString) 
}
Get Reactive
Objective-C Friction 
let textSignal: RACSignal = 
usernameTextField.rac_textSignal() 
textSignal.subscribeNext { 
(text: AnyObject!) -> Void in 
let textString = text as String 
println(textString) 
}
Simplified with Swift 
func subscribeNextAs<T>(nextClosure:(T) -> ()) -> () { 
self.subscribeNext { 
textSignal.subscribeNextAs { 
(text: String) -> () in 
println(text) 
} 
(next: AnyObject!) -> () in 
let nextAsT = next! as T 
nextClosure(nextAsT) 
} 
} 
textSignal.subscribeNext { 
(text: AnyObject!) -> Void in 
let textString = text as String 
println(textString) 
}
Signals 
• A signal emits events 
• next 
• error 
• completed 
• A signal can have none, 
one or more subscribers 
textSignal.subscribeNextAs({ 
(text: String) in 
println(text) 
}, error: { 
(error) in 
// ... 
}, completed: { 
// ... 
})
Events 
Signals can emit none, one or more next events, 
optionally followed by either an error or 
completed 
COMPLETED 
NEXT NEXT ERROR 
NEXT NEXT NEXT NEXT … 
intervals do not 
have to be 
regular!
Signal all things 
• Network request 
• A single next, followed by a completed 
• Large download 
• Multiple next events, representing partial data, 
followed by completed 
• UI control 
• An infinite stream of next events
filter 
let textSignal: RACSignal = usernameTextField.rac_textSignal() 
let filteredText = textSignal.filterAs { 
(text: NSString) -> Bool in 
return text.length > 3 
} 
filteredText.subscribeNextAs { 
(text: String) in 
println(text) 
} 
A filter is a ‘gate’, filtering-out events which do not match 
the given condition
What exactly are events? 
• What does a next event actually look like? 
• Anything! 
• Signals are an interface for handling 
asynchronous events 
• The event contents are context dependant
map 
let textSignal: RACSignal = usernameTextField.rac_textSignal() 
let textLength = textSignal.mapAs { 
(text: NSString) -> NSNumber in 
return text.length 
} 
textLength.subscribeNextAs { 
(length: NSNumber) in 
println(length) 
} 
Transforms each next event (please ignore the types!)
Creating a pipeline 
let textSignal: RACSignal = 
usernameTextField.rac_textSignal() 
let textLength = textSignal.mapAs { 
(text: NSString) -> NSNumber in 
return text.length 
} 
let filteredText = textLength.filterAs { 
(number: NSNumber) -> Bool in 
return number > 3 
} 
filteredText.subscribeNextAs { 
(length: NSNumber) in 
println(length) 
}
Fluent syntax 
usernameTextField 
.rac_textSignal() 
.mapAs { 
(text: NSString) -> NSNumber in 
return text.length 
} 
.filterAs { 
(number: NSNumber) -> Bool in 
return number > 3 
} 
.subscribeNextAs { 
(length: NSNumber) in 
println(length) 
}
number- number- 
ReactiveCocoa Signals 
rac_textSignal- map- filter- subscribeNext-string- 
PUSH% 
Lazy Sequences 
string% number% number% 
lazy% map% filter% generator% 
PULL$
TweetSentiment
searchTextField 
.rac_textSignal() 
.mapAs { 
(text: NSString) -> UIColor in 
text.length <= 3 
? UIColor.lightRedColor() 
: UIColor.whiteColor() 
} 
.setKeyPath("backgroundColor", onObject: searchTextField)
Don’t search for very short 
search terms
Don’t issue a new query on 
each key press
searchTextField 
.rac_textSignal() 
.throttle(0.5) 
.filterAs { 
(text: NSString) -> Bool in 
text.length > 3 
} 
.subscribeNextAs { 
(text: NSString) -> () in 
println(text) 
}
rac_textSignal-filter- 
setKeyPath-thro5le- 
filter- subscribeNext-
Creating 
Signals
private func signalForSearchWithText(text: String) -> RACSignal { 
func requestforSearchText(text: String) -> SLRequest { 
return ... 
} 
return RACSignal.createSignal { 
subscriber -> RACDisposable! in 
let request = requestforSearchText(text) 
let maybeTwitterAccount = self.getTwitterAccount() 
if let twitterAccount = maybeTwitterAccount { 
request.account = twitterAccount 
request.performRequestWithHandler { 
(data, response, _) -> Void in 
if response != nil && response.statusCode == 200 { 
let timelineData = NSJSONSerialization.parseJSONToDictionary(data) 
subscriber.sendNext(timelineData) 
subscriber.sendCompleted() 
} else { 
subscriber.sendError(TwitterInstantError.InvalidResponse.toError()) 
} 
} 
} else { 
subscriber.sendError(TwitterInstantError.NoTwitterAccounts.toError()) 
} 
return nil 
} 
}
searchTextField 
.rac_textSignal() 
.throttle(0.5) 
.filterAs { 
(text: NSString) -> Bool in 
text.length > 3 
} 
.mapAs { 
(text: NSString) -> RACStream in 
self.signalForSearchWithText(text) 
} 
.subscribeNextAs { 
... 
}
searchTextField 
.rac_textSignal() 
.throttle(0.5) 
.filterAs { 
(text: NSString) -> Bool in 
text.length > 3 
} 
.flattenMapAs { 
(text: NSString) -> RACStream in 
self.signalForSearchWithText(text) 
} 
.subscribeNextAs { 
... 
}
searchTextField 
.rac_textSignal() 
.throttle(0.5) 
.filterAs { 
(text: NSString) -> Bool in 
text.length > 3 
} 
.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() 
}
rac_textSignal-filter- 
setKeyPath-thro5le- 
filter- fla5enMap-twi5erSearch-deliverOn- 
subscribeNext-
requestAccessToTwitterSignal() 
.then { 
self.searchTextField.rac_textSignal() 
} 
.filterAs { 
... 
} 
.throttle(0.5) 
...
rac_textSignal-filter- 
setKeyPath-thro5le- 
filter- fla5enMap-twi5erSearch-deliverOn- 
subscribeNext-requestAccess-signal- 
then-
Error 
Handling
requestAccessToTwitterSignal() 
.then { 
self.searchTextField.rac_textSignal() 
} 
.filterAs { 
... 
} 
.throttle(0.5) 
.doNext { 
... 
} 
.flattenMapAs { 
... 
self.signalForSearchWithText(text) 
} 
.deliverOn(RACScheduler.mainThreadScheduler()) 
.subscribeNextAs({ 
... 
}, { 
(error) in 
println(error) 
})
Fetching 
Sentiment Data
Fire a sentiment API request 
for each tweet and merge the 
signals?
Fetch sentiment data when 
cells become visible?
Fetch sentiment data when a 
cell has been visible for a short 
duration?
Signal All 
Things!
RACSignal 
.interval(0.5, onScheduler: 
RACScheduler(priority: RACSchedulerPriorityBackground)) 
.take(1) 
.takeUntil(rac_prepareForReuseSignal) 
.flattenMap { 
(next) -> RACStream in 
self.obtainSentimentSignal(hasTweet) 
} 
.deliverOn(RACScheduler.mainThreadScheduler()) 
.subscribeNextAs { 
(sentiment: String) in 
NSNotificationCenter.defaultCenter() 
.postNotificationName("sentiment", object: sentiment) 
self.sentimentIndicator.backgroundColor = 
self.sentimentToColor(sentiment) 
}
I curried 
a function!
func scale(domainMin: Double, domainMax: Double, screenMin: Double, 
screenMax: Double, pt: Double) -> CGFloat { 
let value = ((pt - domainMin) / (domainMax - domainMin)) 
* (screenMax - screenMin) + screenMin 
return CGFloat(value) 
}
func scale(domainMin: Double, domainMax: Double, screenMin: Double, 
screenMax: Double)(pt: Double) -> CGFloat { 
let value = ((pt - domainMin) / (domainMax - domainMin)) 
* (screenMax - screenMin) + screenMin 
return CGFloat(value) 
}
let xscale = scale(0, Double(maxValue), 35, Double(self.bounds.width - 35)) 
let yscale = scale(0, 3, 0, Double(self.bounds.height)) 
positiveLayer.frame = CGRect(x: xscale(pt: 0), y: yscale(pt: 1), 
width: xdelta(pt1: Double(positive), pt2: 0.0), height: yscale(pt: 1)) 
neutralLayer.frame = ... 
func delta(scale:(Double) -> CGFloat)(pt1: Double, pt2: Double) -> CGFloat { 
return scale(pt1) - scale(pt2) 
} 
let xdelta = delta(xscale)
Better 
Together
Swift loves 
Fluent APIs
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) 
.doNext { 
(any) in 
NSNotificationCenter.defaultCenter().postNotificationName("sentiment", object: "reset") 
} 
.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) 
})
http://stackoverflow.com/questions/3124001/fluent-interface-pattern-in-objective-c
http://stackoverflow.com/questions/3124001/fluent-interface-pattern-in-objective-c
[[[[[[[[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); 
}];
ReactiveCocoa 
hates state
39 constants 
12 variables 
6 outlets (not my fault!) 
1 UIWindow 
5 UI state variables
ReactiveCocoa and Swift 
Better Together 
@ColinEberhardt 
ShinobiControls 
TwitterSentiment: 
https://github.com/ColinEberhardt/ReactiveSwiftLondon 
MVVM with ReactiveCocoa and Swift: 
https://github.com/ColinEberhardt/ReactiveSwiftFlickrSearch 
Tutorials: 
http://www.raywenderlich.com/u/ColinEberhardt

Contenu connexe

Tendances

Swift Sequences & Collections
Swift Sequences & CollectionsSwift Sequences & Collections
Swift Sequences & CollectionsCocoaHeads France
 
Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...Mario Fusco
 
Functional Reactive Programming (FRP): Working with RxJS
Functional Reactive Programming (FRP): Working with RxJSFunctional Reactive Programming (FRP): Working with RxJS
Functional Reactive Programming (FRP): Working with RxJSOswald Campesato
 
Functional programming in Javascript
Functional programming in JavascriptFunctional programming in Javascript
Functional programming in JavascriptKnoldus Inc.
 
Streaming Dataflow with Apache Flink
Streaming Dataflow with Apache Flink Streaming Dataflow with Apache Flink
Streaming Dataflow with Apache Flink huguk
 
Luis Atencio on RxJS
Luis Atencio on RxJSLuis Atencio on RxJS
Luis Atencio on RxJSLuis Atencio
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptRxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptViliam Elischer
 
Wrapping java in awesomeness aka condensator
Wrapping java in awesomeness aka condensatorWrapping java in awesomeness aka condensator
Wrapping java in awesomeness aka condensatorFlowa Oy
 
Reactive cocoa
Reactive cocoaReactive cocoa
Reactive cocoaiacisclo
 
JavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good PartsJavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good PartsKonrad Malawski
 

Tendances (20)

Rxjs ppt
Rxjs pptRxjs ppt
Rxjs ppt
 
Swift Sequences & Collections
Swift Sequences & CollectionsSwift Sequences & Collections
Swift Sequences & Collections
 
Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...Reactive Programming for a demanding world: building event-driven and respons...
Reactive Programming for a demanding world: building event-driven and respons...
 
Functional Reactive Programming (FRP): Working with RxJS
Functional Reactive Programming (FRP): Working with RxJSFunctional Reactive Programming (FRP): Working with RxJS
Functional Reactive Programming (FRP): Working with RxJS
 
Rxjs ngvikings
Rxjs ngvikingsRxjs ngvikings
Rxjs ngvikings
 
Oop assignment 02
Oop assignment 02Oop assignment 02
Oop assignment 02
 
Functional programming in Javascript
Functional programming in JavascriptFunctional programming in Javascript
Functional programming in Javascript
 
Streaming Dataflow with Apache Flink
Streaming Dataflow with Apache Flink Streaming Dataflow with Apache Flink
Streaming Dataflow with Apache Flink
 
Reactive Java (33rd Degree)
Reactive Java (33rd Degree)Reactive Java (33rd Degree)
Reactive Java (33rd Degree)
 
Luis Atencio on RxJS
Luis Atencio on RxJSLuis Atencio on RxJS
Luis Atencio on RxJS
 
Intro to Akka Streams
Intro to Akka StreamsIntro to Akka Streams
Intro to Akka Streams
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptRxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScript
 
Wrapping java in awesomeness aka condensator
Wrapping java in awesomeness aka condensatorWrapping java in awesomeness aka condensator
Wrapping java in awesomeness aka condensator
 
Parallel streams in java 8
Parallel streams in java 8Parallel streams in java 8
Parallel streams in java 8
 
Rx – reactive extensions
Rx – reactive extensionsRx – reactive extensions
Rx – reactive extensions
 
Reactive cocoa
Reactive cocoaReactive cocoa
Reactive cocoa
 
Map kit light
Map kit lightMap kit light
Map kit light
 
Monads in Swift
Monads in SwiftMonads in Swift
Monads in Swift
 
JavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good PartsJavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good Parts
 
Cocoa heads 09112017
Cocoa heads 09112017Cocoa heads 09112017
Cocoa heads 09112017
 

En vedette

ReactiveCocoa - Functional Reactive Programming concepts in iOS
ReactiveCocoa - Functional Reactive Programming concepts in iOSReactiveCocoa - Functional Reactive Programming concepts in iOS
ReactiveCocoa - Functional Reactive Programming concepts in iOSAndrei Popa
 
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with SwiftStanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with SwiftStanfy
 
MV(C, mvvm) in iOS and ReactiveCocoa
MV(C, mvvm) in iOS and ReactiveCocoaMV(C, mvvm) in iOS and ReactiveCocoa
MV(C, mvvm) in iOS and ReactiveCocoaYi-Shou Chen
 
in in der 響應式編程
in in der 響應式編程in in der 響應式編程
in in der 響應式編程景隆 張
 
Introduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoaIntroduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoaFlorent Pillet
 
ReactiveCocoa - TDC 2016
ReactiveCocoa - TDC 2016ReactiveCocoa - TDC 2016
ReactiveCocoa - TDC 2016vinciusreal
 
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...Stanfy
 

En vedette (7)

ReactiveCocoa - Functional Reactive Programming concepts in iOS
ReactiveCocoa - Functional Reactive Programming concepts in iOSReactiveCocoa - Functional Reactive Programming concepts in iOS
ReactiveCocoa - Functional Reactive Programming concepts in iOS
 
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with SwiftStanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
 
MV(C, mvvm) in iOS and ReactiveCocoa
MV(C, mvvm) in iOS and ReactiveCocoaMV(C, mvvm) in iOS and ReactiveCocoa
MV(C, mvvm) in iOS and ReactiveCocoa
 
in in der 響應式編程
in in der 響應式編程in in der 響應式編程
in in der 響應式編程
 
Introduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoaIntroduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoa
 
ReactiveCocoa - TDC 2016
ReactiveCocoa - TDC 2016ReactiveCocoa - TDC 2016
ReactiveCocoa - TDC 2016
 
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
Stanfy MadCode Meetup #11: Why do you need to switch from Obj-C to Swift, or ...
 

Similaire à ReactiveCocoa and Swift, Better Together

Kafka Summit NYC 2017 - Easy, Scalable, Fault-tolerant Stream Processing with...
Kafka Summit NYC 2017 - Easy, Scalable, Fault-tolerant Stream Processing with...Kafka Summit NYC 2017 - Easy, Scalable, Fault-tolerant Stream Processing with...
Kafka Summit NYC 2017 - Easy, Scalable, Fault-tolerant Stream Processing with...confluent
 
Reactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftReactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftFlorent Pillet
 
Scala Turkiye 2013-02-07 Sunumu
Scala Turkiye 2013-02-07 SunumuScala Turkiye 2013-02-07 Sunumu
Scala Turkiye 2013-02-07 SunumuVolkan Yazıcı
 
Legacy lambda code
Legacy lambda codeLegacy lambda code
Legacy lambda codePeter Lawrey
 
All you need to know about the JavaScript event loop
All you need to know about the JavaScript event loopAll you need to know about the JavaScript event loop
All you need to know about the JavaScript event loopSaša Tatar
 
Real Time Big Data Management
Real Time Big Data ManagementReal Time Big Data Management
Real Time Big Data ManagementAlbert Bifet
 
mobl - model-driven engineering lecture
mobl - model-driven engineering lecturemobl - model-driven engineering lecture
mobl - model-driven engineering lecturezefhemel
 
JavaScript Objects
JavaScript ObjectsJavaScript Objects
JavaScript ObjectsReem Alattas
 
What's new with Apache Spark's Structured Streaming?
What's new with Apache Spark's Structured Streaming?What's new with Apache Spark's Structured Streaming?
What's new with Apache Spark's Structured Streaming?Miklos Christine
 
Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraDeependra Ariyadewa
 
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)DataStax Academy
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
mobl presentation @ IHomer
mobl presentation @ IHomermobl presentation @ IHomer
mobl presentation @ IHomerzefhemel
 
Introduction to Spark with Scala
Introduction to Spark with ScalaIntroduction to Spark with Scala
Introduction to Spark with ScalaHimanshu Gupta
 
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...DataWorks Summit
 

Similaire à ReactiveCocoa and Swift, Better Together (20)

Kafka Summit NYC 2017 - Easy, Scalable, Fault-tolerant Stream Processing with...
Kafka Summit NYC 2017 - Easy, Scalable, Fault-tolerant Stream Processing with...Kafka Summit NYC 2017 - Easy, Scalable, Fault-tolerant Stream Processing with...
Kafka Summit NYC 2017 - Easy, Scalable, Fault-tolerant Stream Processing with...
 
Reactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftReactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwift
 
Scala Turkiye 2013-02-07 Sunumu
Scala Turkiye 2013-02-07 SunumuScala Turkiye 2013-02-07 Sunumu
Scala Turkiye 2013-02-07 Sunumu
 
DIWE - Advanced PHP Concepts
DIWE - Advanced PHP ConceptsDIWE - Advanced PHP Concepts
DIWE - Advanced PHP Concepts
 
Legacy lambda code
Legacy lambda codeLegacy lambda code
Legacy lambda code
 
All you need to know about the JavaScript event loop
All you need to know about the JavaScript event loopAll you need to know about the JavaScript event loop
All you need to know about the JavaScript event loop
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
 
CAVE Overview
CAVE OverviewCAVE Overview
CAVE Overview
 
Real Time Big Data Management
Real Time Big Data ManagementReal Time Big Data Management
Real Time Big Data Management
 
mobl - model-driven engineering lecture
mobl - model-driven engineering lecturemobl - model-driven engineering lecture
mobl - model-driven engineering lecture
 
JavaScript Objects
JavaScript ObjectsJavaScript Objects
JavaScript Objects
 
Rxjs marble-testing
Rxjs marble-testingRxjs marble-testing
Rxjs marble-testing
 
What's new with Apache Spark's Structured Streaming?
What's new with Apache Spark's Structured Streaming?What's new with Apache Spark's Structured Streaming?
What's new with Apache Spark's Structured Streaming?
 
Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and Cassandra
 
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
WattGo: Analyses temps-réél de series temporelles avec Spark et Solr (Français)
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
mobl presentation @ IHomer
mobl presentation @ IHomermobl presentation @ IHomer
mobl presentation @ IHomer
 
Introduction to Spark with Scala
Introduction to Spark with ScalaIntroduction to Spark with Scala
Introduction to Spark with Scala
 
Rx workshop
Rx workshopRx workshop
Rx workshop
 
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...
 

Dernier

Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfOverkill Security
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native ApplicationsWSO2
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKJago de Vreede
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfOverkill Security
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Zilliz
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024The Digital Insurer
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...apidays
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusZilliz
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 

Dernier (20)

Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 

ReactiveCocoa and Swift, Better Together

  • 1. ReactiveCocoa and Swift Better Together @ColinEberhardt ShinobiControls
  • 3.
  • 5.
  • 6. Functional Programming + Reactive Programming = Functional Reactive Programming
  • 8. Every line of code we write is executed in reaction to an event
  • 9. But … these events come in many different forms KVO delegates NSNotification target-action callbacks
  • 10. ReactiveCocoa provides a common interface for all events!
  • 11. … this allows us to define a language for manipulating, transforming and coordinating events
  • 13. Get Reactive let textSignal: RACSignal = usernameTextField.rac_textSignal() textSignal.subscribeNext { (text: AnyObject!) -> Void in let textString = text as String println(textString) }
  • 15. Objective-C Friction let textSignal: RACSignal = usernameTextField.rac_textSignal() textSignal.subscribeNext { (text: AnyObject!) -> Void in let textString = text as String println(textString) }
  • 16. Simplified with Swift func subscribeNextAs<T>(nextClosure:(T) -> ()) -> () { self.subscribeNext { textSignal.subscribeNextAs { (text: String) -> () in println(text) } (next: AnyObject!) -> () in let nextAsT = next! as T nextClosure(nextAsT) } } textSignal.subscribeNext { (text: AnyObject!) -> Void in let textString = text as String println(textString) }
  • 17. Signals • A signal emits events • next • error • completed • A signal can have none, one or more subscribers textSignal.subscribeNextAs({ (text: String) in println(text) }, error: { (error) in // ... }, completed: { // ... })
  • 18. Events Signals can emit none, one or more next events, optionally followed by either an error or completed COMPLETED NEXT NEXT ERROR NEXT NEXT NEXT NEXT … intervals do not have to be regular!
  • 19. Signal all things • Network request • A single next, followed by a completed • Large download • Multiple next events, representing partial data, followed by completed • UI control • An infinite stream of next events
  • 20. filter let textSignal: RACSignal = usernameTextField.rac_textSignal() let filteredText = textSignal.filterAs { (text: NSString) -> Bool in return text.length > 3 } filteredText.subscribeNextAs { (text: String) in println(text) } A filter is a ‘gate’, filtering-out events which do not match the given condition
  • 21.
  • 22. What exactly are events? • What does a next event actually look like? • Anything! • Signals are an interface for handling asynchronous events • The event contents are context dependant
  • 23. map let textSignal: RACSignal = usernameTextField.rac_textSignal() let textLength = textSignal.mapAs { (text: NSString) -> NSNumber in return text.length } textLength.subscribeNextAs { (length: NSNumber) in println(length) } Transforms each next event (please ignore the types!)
  • 24.
  • 25. Creating a pipeline let textSignal: RACSignal = usernameTextField.rac_textSignal() let textLength = textSignal.mapAs { (text: NSString) -> NSNumber in return text.length } let filteredText = textLength.filterAs { (number: NSNumber) -> Bool in return number > 3 } filteredText.subscribeNextAs { (length: NSNumber) in println(length) }
  • 26. Fluent syntax usernameTextField .rac_textSignal() .mapAs { (text: NSString) -> NSNumber in return text.length } .filterAs { (number: NSNumber) -> Bool in return number > 3 } .subscribeNextAs { (length: NSNumber) in println(length) }
  • 27. number- number- ReactiveCocoa Signals rac_textSignal- map- filter- subscribeNext-string- PUSH% Lazy Sequences string% number% number% lazy% map% filter% generator% PULL$
  • 29.
  • 30. searchTextField .rac_textSignal() .mapAs { (text: NSString) -> UIColor in text.length <= 3 ? UIColor.lightRedColor() : UIColor.whiteColor() } .setKeyPath("backgroundColor", onObject: searchTextField)
  • 31. Don’t search for very short search terms
  • 32. Don’t issue a new query on each key press
  • 33. searchTextField .rac_textSignal() .throttle(0.5) .filterAs { (text: NSString) -> Bool in text.length > 3 } .subscribeNextAs { (text: NSString) -> () in println(text) }
  • 36. private func signalForSearchWithText(text: String) -> RACSignal { func requestforSearchText(text: String) -> SLRequest { return ... } return RACSignal.createSignal { subscriber -> RACDisposable! in let request = requestforSearchText(text) let maybeTwitterAccount = self.getTwitterAccount() if let twitterAccount = maybeTwitterAccount { request.account = twitterAccount request.performRequestWithHandler { (data, response, _) -> Void in if response != nil && response.statusCode == 200 { let timelineData = NSJSONSerialization.parseJSONToDictionary(data) subscriber.sendNext(timelineData) subscriber.sendCompleted() } else { subscriber.sendError(TwitterInstantError.InvalidResponse.toError()) } } } else { subscriber.sendError(TwitterInstantError.NoTwitterAccounts.toError()) } return nil } }
  • 37. searchTextField .rac_textSignal() .throttle(0.5) .filterAs { (text: NSString) -> Bool in text.length > 3 } .mapAs { (text: NSString) -> RACStream in self.signalForSearchWithText(text) } .subscribeNextAs { ... }
  • 38. searchTextField .rac_textSignal() .throttle(0.5) .filterAs { (text: NSString) -> Bool in text.length > 3 } .flattenMapAs { (text: NSString) -> RACStream in self.signalForSearchWithText(text) } .subscribeNextAs { ... }
  • 39. searchTextField .rac_textSignal() .throttle(0.5) .filterAs { (text: NSString) -> Bool in text.length > 3 } .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() }
  • 40. rac_textSignal-filter- setKeyPath-thro5le- filter- fla5enMap-twi5erSearch-deliverOn- subscribeNext-
  • 41. requestAccessToTwitterSignal() .then { self.searchTextField.rac_textSignal() } .filterAs { ... } .throttle(0.5) ...
  • 42. rac_textSignal-filter- setKeyPath-thro5le- filter- fla5enMap-twi5erSearch-deliverOn- subscribeNext-requestAccess-signal- then-
  • 44. requestAccessToTwitterSignal() .then { self.searchTextField.rac_textSignal() } .filterAs { ... } .throttle(0.5) .doNext { ... } .flattenMapAs { ... self.signalForSearchWithText(text) } .deliverOn(RACScheduler.mainThreadScheduler()) .subscribeNextAs({ ... }, { (error) in println(error) })
  • 46. Fire a sentiment API request for each tweet and merge the signals?
  • 47. Fetch sentiment data when cells become visible?
  • 48. Fetch sentiment data when a cell has been visible for a short duration?
  • 50. RACSignal .interval(0.5, onScheduler: RACScheduler(priority: RACSchedulerPriorityBackground)) .take(1) .takeUntil(rac_prepareForReuseSignal) .flattenMap { (next) -> RACStream in self.obtainSentimentSignal(hasTweet) } .deliverOn(RACScheduler.mainThreadScheduler()) .subscribeNextAs { (sentiment: String) in NSNotificationCenter.defaultCenter() .postNotificationName("sentiment", object: sentiment) self.sentimentIndicator.backgroundColor = self.sentimentToColor(sentiment) }
  • 51.
  • 52. I curried a function!
  • 53.
  • 54. func scale(domainMin: Double, domainMax: Double, screenMin: Double, screenMax: Double, pt: Double) -> CGFloat { let value = ((pt - domainMin) / (domainMax - domainMin)) * (screenMax - screenMin) + screenMin return CGFloat(value) }
  • 55. func scale(domainMin: Double, domainMax: Double, screenMin: Double, screenMax: Double)(pt: Double) -> CGFloat { let value = ((pt - domainMin) / (domainMax - domainMin)) * (screenMax - screenMin) + screenMin return CGFloat(value) }
  • 56. let xscale = scale(0, Double(maxValue), 35, Double(self.bounds.width - 35)) let yscale = scale(0, 3, 0, Double(self.bounds.height)) positiveLayer.frame = CGRect(x: xscale(pt: 0), y: yscale(pt: 1), width: xdelta(pt1: Double(positive), pt2: 0.0), height: yscale(pt: 1)) neutralLayer.frame = ... func delta(scale:(Double) -> CGFloat)(pt1: Double, pt2: Double) -> CGFloat { return scale(pt1) - scale(pt2) } let xdelta = delta(xscale)
  • 57.
  • 60. 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) .doNext { (any) in NSNotificationCenter.defaultCenter().postNotificationName("sentiment", object: "reset") } .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) })
  • 63. [[[[[[[[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); }];
  • 65. 39 constants 12 variables 6 outlets (not my fault!) 1 UIWindow 5 UI state variables
  • 66. ReactiveCocoa and Swift Better Together @ColinEberhardt ShinobiControls TwitterSentiment: https://github.com/ColinEberhardt/ReactiveSwiftLondon MVVM with ReactiveCocoa and Swift: https://github.com/ColinEberhardt/ReactiveSwiftFlickrSearch Tutorials: http://www.raywenderlich.com/u/ColinEberhardt