now you're thinking with signals
DESCRIPTION
A talk on FRP originally presented at the /dev/world/2015 conference.TRANSCRIPT
-
Now You're Thinking With Signals!
A ReactiveCocoa Adventure
-
Who is this guy?
Jeames BoneiOS Software Engineer @ Outware Mobile@jeamesbone on all the things.
-
FunctionalReactive
Programming
-
What is FRP?
-
F for Functional
Immutable Stateless
-
R for Reactive
What instead of how Derived stateInstead of telling a computer how to do its job, why don't we just tell it what it's job is and let it figure the rest out?
-
Functional Reactive Programming Combines functional and reactive paradigms. Uses streams of values and transformations on streams to
derive state.
-
Why FRPUIs are big, messy, mutable, stateful bags of sadness. Reduce mutable state Simpler programs Better code
-
ReactiveCocoa
-
Signals
-
Events
public enum Event { /// A value provided by the signal. case Next(T)
/// The signal terminated because of an error. No further events will be /// received. case Error(E)
/// The signal successfully terminated. No further events will be received. case Completed
/// Event production on the signal has been interrupted. No further events /// will be received. case Interrupted}
-
Signals
-
Signals in ReactiveCocoa 3
Signal
Signals model an existing stream of events in your app. User input Notifications Location Updates
-
SignalProducers
SignalProducer
SignalProducers model the results of some work. Network requests A modal view A watch connectivity request
-
Errors
Errors are passed on to the next step in the stream. If any point of the stream fails, we can handle this in one
place. Railway oriented programming
-
OperatorsTo the internet!
-
Example
-
let searchStrings = textField.rac_textSignal() .toSignalProducer() .map { text in text as! String }
-
let searchResults = searchStrings .flatMap(.Latest) { query in let URLRequest = self.searchRequestWithEscapedQuery(query) return NSURLSession.sharedSession().rac_dataWithRequest(URLRequest) } .map { data, URLResponse in let string = String(data: data, encoding: NSUTF8StringEncoding)! return parseJSONResultsFromString(string) } .map { JSONResults in return self.parseModelFromJSON(JSONResults) } .observeOn(UIScheduler())
-
searchResults.start(next: { model in self.updateUIWithModel(model)})
-
Now for magic
-
let searchResults = searchStrings .flatMap(.Latest) { query in let URLRequest = self.searchRequestWithEscapedQuery(query) return NSURLSession.sharedSession().rac_dataWithRequest(URLRequest) .retry(3) .catch { error in self.displayError(error) return SignalProducer.empty } } .map { data, URLResponse in let string = String(data: data, encoding: NSUTF8StringEncoding)! return parseJSONResultsFromString(string) } .map { JSONResults in return self.parseModelFromJSON(JSONResults) } .observeOn(UIScheduler())
-
But wait there's more!
-
let searchStrings = textField.rac_textSignal() .toSignalProducer() .map { text in text as! String } .filter { text in text.characters.count > 4 } .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)
-
What has this given us?
Less code Maintainable code Readable code
-
Where to next? http://reactivecocoa.io/ Try it!
-
Thanks!Questions?