SlideShare a Scribd company logo
ReactiveCocoa and Swift 
Better Together 
@ColinEberhardt 
ShinobiControls
www.shinobicontrols.com
ReactiveCocoa and Swift, Better Together
What is 
ReactiveCocoa?
ReactiveCocoa and Swift, Better Together
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
ReactiveCocoa and Swift, Better Together
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!)
ReactiveCocoa and Swift, Better Together
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
ReactiveCocoa and Swift, Better Together
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) 
}
ReactiveCocoa and Swift, Better Together
I curried 
a function!
ReactiveCocoa and Swift, Better Together
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)
ReactiveCocoa and Swift, Better Together
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
Ad

Recommended

Intro to ReactiveCocoa
Intro to ReactiveCocoa
kleneau
 
Reactive cocoa made Simple with Swift
Reactive cocoa made Simple with Swift
Colin Eberhardt
 
An Introduction to Reactive Cocoa
An Introduction to Reactive Cocoa
SmartLogic
 
ReactiveCocoa in Practice
ReactiveCocoa in Practice
Outware Mobile
 
Learn You a ReactiveCocoa for Great Good
Learn You a ReactiveCocoa for Great Good
Jason Larsen
 
ReactiveCocoa Goodness - Part I of II
ReactiveCocoa Goodness - Part I of II
manuelmaly
 
Introduction to RxJS
Introduction to RxJS
Brainhub
 
Angular and The Case for RxJS
Angular and The Case for RxJS
Sandi Barr
 
Rxjs ppt
Rxjs ppt
Christoffer Noring
 
Swift Sequences & Collections
Swift Sequences & Collections
CocoaHeads France
 
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 RxJS
Oswald Campesato
 
Rxjs ngvikings
Rxjs ngvikings
Christoffer Noring
 
Oop assignment 02
Oop assignment 02
MamoonKhan39
 
Functional programming in Javascript
Functional programming in Javascript
Knoldus Inc.
 
Streaming Dataflow with Apache Flink
Streaming Dataflow with Apache Flink
huguk
 
Reactive Java (33rd Degree)
Reactive Java (33rd Degree)
Tomasz Kowalczewski
 
Luis Atencio on RxJS
Luis Atencio on RxJS
Luis Atencio
 
Intro to Akka Streams
Intro to Akka Streams
Michael Kendra
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScript
Viliam Elischer
 
Wrapping java in awesomeness aka condensator
Wrapping java in awesomeness aka condensator
Flowa Oy
 
Parallel streams in java 8
Parallel streams in java 8
David Gómez García
 
Rx – reactive extensions
Rx – reactive extensions
Voislav Mishevski
 
Reactive cocoa
Reactive cocoa
iacisclo
 
Map kit light
Map kit light
CocoaHeads France
 
Monads in Swift
Monads in Swift
Vincent Pradeilles
 
JavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good Parts
Konrad Malawski
 
Cocoa heads 09112017
Cocoa heads 09112017
Vincent Pradeilles
 
ReactiveCocoa - Functional Reactive Programming concepts in iOS
ReactiveCocoa - Functional Reactive Programming concepts in iOS
Andrei Popa
 
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy
 

More Related Content

What's hot (20)

Rxjs ppt
Rxjs ppt
Christoffer Noring
 
Swift Sequences & Collections
Swift Sequences & Collections
CocoaHeads France
 
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 RxJS
Oswald Campesato
 
Rxjs ngvikings
Rxjs ngvikings
Christoffer Noring
 
Oop assignment 02
Oop assignment 02
MamoonKhan39
 
Functional programming in Javascript
Functional programming in Javascript
Knoldus Inc.
 
Streaming Dataflow with Apache Flink
Streaming Dataflow with Apache Flink
huguk
 
Reactive Java (33rd Degree)
Reactive Java (33rd Degree)
Tomasz Kowalczewski
 
Luis Atencio on RxJS
Luis Atencio on RxJS
Luis Atencio
 
Intro to Akka Streams
Intro to Akka Streams
Michael Kendra
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScript
Viliam Elischer
 
Wrapping java in awesomeness aka condensator
Wrapping java in awesomeness aka condensator
Flowa Oy
 
Parallel streams in java 8
Parallel streams in java 8
David Gómez García
 
Rx – reactive extensions
Rx – reactive extensions
Voislav Mishevski
 
Reactive cocoa
Reactive cocoa
iacisclo
 
Map kit light
Map kit light
CocoaHeads France
 
Monads in Swift
Monads in Swift
Vincent Pradeilles
 
JavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good Parts
Konrad Malawski
 
Cocoa heads 09112017
Cocoa heads 09112017
Vincent Pradeilles
 
Swift Sequences & Collections
Swift Sequences & Collections
CocoaHeads France
 
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 RxJS
Oswald Campesato
 
Functional programming in Javascript
Functional programming in Javascript
Knoldus Inc.
 
Streaming Dataflow with Apache Flink
Streaming Dataflow with Apache Flink
huguk
 
Luis Atencio on RxJS
Luis Atencio on RxJS
Luis Atencio
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScript
Viliam Elischer
 
Wrapping java in awesomeness aka condensator
Wrapping java in awesomeness aka condensator
Flowa Oy
 
Reactive cocoa
Reactive cocoa
iacisclo
 
JavaOne 2013: Java 8 - The Good Parts
JavaOne 2013: Java 8 - The Good Parts
Konrad Malawski
 

Viewers also liked (7)

ReactiveCocoa - Functional Reactive Programming concepts in iOS
ReactiveCocoa - Functional Reactive Programming concepts in iOS
Andrei Popa
 
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy
 
MV(C, mvvm) in iOS and ReactiveCocoa
MV(C, mvvm) in iOS and ReactiveCocoa
Yi-Shou Chen
 
in in der 響應式編程
in in der 響應式編程
景隆 張
 
Introduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoa
Florent Pillet
 
ReactiveCocoa - TDC 2016
ReactiveCocoa - TDC 2016
vinciusreal
 
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
 
ReactiveCocoa - Functional Reactive Programming concepts in iOS
ReactiveCocoa - Functional Reactive Programming concepts in iOS
Andrei Popa
 
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy MadCode Meetup #9: Functional Programming 101 with Swift
Stanfy
 
MV(C, mvvm) in iOS and ReactiveCocoa
MV(C, mvvm) in iOS and ReactiveCocoa
Yi-Shou Chen
 
in in der 響應式編程
in in der 響應式編程
景隆 張
 
Introduction to reactive programming & ReactiveCocoa
Introduction to reactive programming & ReactiveCocoa
Florent Pillet
 
ReactiveCocoa - TDC 2016
ReactiveCocoa - TDC 2016
vinciusreal
 
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
 
Ad

Similar to 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...
confluent
 
Reactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwift
Florent Pillet
 
Scala Turkiye 2013-02-07 Sunumu
Scala Turkiye 2013-02-07 Sunumu
Volkan Yazıcı
 
DIWE - Advanced PHP Concepts
DIWE - Advanced PHP Concepts
Rasan Samarasinghe
 
Legacy lambda code
Legacy lambda code
Peter Lawrey
 
All you need to know about the JavaScript event loop
All you need to know about the JavaScript event loop
Saša Tatar
 
Spark workshop
Spark workshop
Wojciech Pituła
 
CAVE Overview
CAVE Overview
vdumitrescu
 
Real Time Big Data Management
Real Time Big Data Management
Albert Bifet
 
mobl - model-driven engineering lecture
mobl - model-driven engineering lecture
zefhemel
 
JavaScript Objects
JavaScript Objects
Reem Alattas
 
Rxjs marble-testing
Rxjs marble-testing
Christoffer Noring
 
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 Cassandra
Deependra 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)
DataStax Academy
 
Refactoring to Macros with Clojure
Refactoring to Macros with Clojure
Dmitry Buzdin
 
mobl presentation @ IHomer
mobl presentation @ IHomer
zefhemel
 
Introduction to Spark with Scala
Introduction to Spark with Scala
Himanshu Gupta
 
Rx workshop
Rx workshop
Ryan Riley
 
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...
DataWorks Summit
 
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 RxSwift
Florent Pillet
 
Scala Turkiye 2013-02-07 Sunumu
Scala Turkiye 2013-02-07 Sunumu
Volkan Yazıcı
 
Legacy lambda code
Legacy lambda code
Peter Lawrey
 
All you need to know about the JavaScript event loop
All you need to know about the JavaScript event loop
Saša Tatar
 
Real Time Big Data Management
Real Time Big Data Management
Albert Bifet
 
mobl - model-driven engineering lecture
mobl - model-driven engineering lecture
zefhemel
 
JavaScript Objects
JavaScript Objects
Reem Alattas
 
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 Cassandra
Deependra 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)
DataStax Academy
 
Refactoring to Macros with Clojure
Refactoring to Macros with Clojure
Dmitry Buzdin
 
mobl presentation @ IHomer
mobl presentation @ IHomer
zefhemel
 
Introduction to Spark with Scala
Introduction to Spark with Scala
Himanshu Gupta
 
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...
Easy, Scalable, Fault-tolerant stream processing with Structured Streaming in...
DataWorks Summit
 
Ad

Recently uploaded (20)

Integration of Utility Data into 3D BIM Models Using a 3D Solids Modeling Wor...
Integration of Utility Data into 3D BIM Models Using a 3D Solids Modeling Wor...
Safe Software
 
OWASP Barcelona 2025 Threat Model Library
OWASP Barcelona 2025 Threat Model Library
PetraVukmirovic
 
Crypto Super 500 - 14th Report - June2025.pdf
Crypto Super 500 - 14th Report - June2025.pdf
Stephen Perrenod
 
Artificial Intelligence in the Nonprofit Boardroom.pdf
Artificial Intelligence in the Nonprofit Boardroom.pdf
OnBoard
 
ENERGY CONSUMPTION CALCULATION IN ENERGY-EFFICIENT AIR CONDITIONER.pdf
ENERGY CONSUMPTION CALCULATION IN ENERGY-EFFICIENT AIR CONDITIONER.pdf
Muhammad Rizwan Akram
 
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
Safe Software
 
Data Validation and System Interoperability
Data Validation and System Interoperability
Safe Software
 
FIDO Seminar: Evolving Landscape of Post-Quantum Cryptography.pptx
FIDO Seminar: Evolving Landscape of Post-Quantum Cryptography.pptx
FIDO Alliance
 
Supporting the NextGen 911 Digital Transformation with FME
Supporting the NextGen 911 Digital Transformation with FME
Safe Software
 
MuleSoft for AgentForce : Topic Center and API Catalog
MuleSoft for AgentForce : Topic Center and API Catalog
shyamraj55
 
Kubernetes Security Act Now Before It’s Too Late
Kubernetes Security Act Now Before It’s Too Late
Michael Furman
 
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
Safe Software
 
Mastering AI Workflows with FME - Peak of Data & AI 2025
Mastering AI Workflows with FME - Peak of Data & AI 2025
Safe Software
 
TrustArc Webinar - 2025 Global Privacy Survey
TrustArc Webinar - 2025 Global Privacy Survey
TrustArc
 
AI vs Human Writing: Can You Tell the Difference?
AI vs Human Writing: Can You Tell the Difference?
Shashi Sathyanarayana, Ph.D
 
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik
 
Providing an OGC API Processes REST Interface for FME Flow
Providing an OGC API Processes REST Interface for FME Flow
Safe Software
 
SAP Modernization Strategies for a Successful S/4HANA Journey.pdf
SAP Modernization Strategies for a Successful S/4HANA Journey.pdf
Precisely
 
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Alliance
 
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
AmirStern2
 
Integration of Utility Data into 3D BIM Models Using a 3D Solids Modeling Wor...
Integration of Utility Data into 3D BIM Models Using a 3D Solids Modeling Wor...
Safe Software
 
OWASP Barcelona 2025 Threat Model Library
OWASP Barcelona 2025 Threat Model Library
PetraVukmirovic
 
Crypto Super 500 - 14th Report - June2025.pdf
Crypto Super 500 - 14th Report - June2025.pdf
Stephen Perrenod
 
Artificial Intelligence in the Nonprofit Boardroom.pdf
Artificial Intelligence in the Nonprofit Boardroom.pdf
OnBoard
 
ENERGY CONSUMPTION CALCULATION IN ENERGY-EFFICIENT AIR CONDITIONER.pdf
ENERGY CONSUMPTION CALCULATION IN ENERGY-EFFICIENT AIR CONDITIONER.pdf
Muhammad Rizwan Akram
 
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
National Fuels Treatments Initiative: Building a Seamless Map of Hazardous Fu...
Safe Software
 
Data Validation and System Interoperability
Data Validation and System Interoperability
Safe Software
 
FIDO Seminar: Evolving Landscape of Post-Quantum Cryptography.pptx
FIDO Seminar: Evolving Landscape of Post-Quantum Cryptography.pptx
FIDO Alliance
 
Supporting the NextGen 911 Digital Transformation with FME
Supporting the NextGen 911 Digital Transformation with FME
Safe Software
 
MuleSoft for AgentForce : Topic Center and API Catalog
MuleSoft for AgentForce : Topic Center and API Catalog
shyamraj55
 
Kubernetes Security Act Now Before It’s Too Late
Kubernetes Security Act Now Before It’s Too Late
Michael Furman
 
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
Safe Software
 
Mastering AI Workflows with FME - Peak of Data & AI 2025
Mastering AI Workflows with FME - Peak of Data & AI 2025
Safe Software
 
TrustArc Webinar - 2025 Global Privacy Survey
TrustArc Webinar - 2025 Global Privacy Survey
TrustArc
 
AI vs Human Writing: Can You Tell the Difference?
AI vs Human Writing: Can You Tell the Difference?
Shashi Sathyanarayana, Ph.D
 
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik - Passionate Tech Enthusiast
Raman Bhaumik
 
Providing an OGC API Processes REST Interface for FME Flow
Providing an OGC API Processes REST Interface for FME Flow
Safe Software
 
SAP Modernization Strategies for a Successful S/4HANA Journey.pdf
SAP Modernization Strategies for a Successful S/4HANA Journey.pdf
Precisely
 
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Alliance
 
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
AmirStern2
 

ReactiveCocoa and Swift, Better Together

  • 1. ReactiveCocoa and Swift Better Together @ColinEberhardt ShinobiControls
  • 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
  • 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!)
  • 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$
  • 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) }
  • 52. I curried a function!
  • 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)
  • 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