View
987
Download
4
Category
Tags:
Preview:
DESCRIPTION
#MBLTdev: Конференция мобильных разработчиков Спикер: Ash Furrow iOS-разработчик, Artsy http://mbltdev.ru/
Citation preview
Functional Reactive Programming in Swift
Ash Furrow
Agenda
1. Func'onal reac've programming uses a concept call “signals”
2. Reac'veCocoa uses signals to reduce mutable state
3. Ge>ng started is easy
Signals
Signals• At the core of FRP are signals
• Signals send values over 'me, un'l they complete or error out
• A signal never sends anything aGer comple'ng or erring
• A signal either completes, or errors out, but never both
• A signal has no concept of a “current value” or “past values”
• It’s like a pipe
Signals
• Signals can be chained to transform the values that they send
• This is core to FRP: data transforma'on of values sent over 'me
• In math terms, it’s f(g(y))
ReactiveCocoa
• Reac'veCocoa is a framework developed by GitHub
• Reac'veCocoa is an implementa'on of FRP on iOS/OS X
• It’s currently being revamped with SwiG to version 3.0
Signals• Signals are typically built on KVO
• They can also be created manually
• Crea'ng a signal is easy
• RACObserve()
• Wraps a dynamic property
• Sends a new value for updated property values
Signals
• Subscribe to a signal to perform side-‐effects when it sends new values
• Or use bindings (later)
public func RACObserve(target: NSObject!, keyPath: String) -> RACSignal { return target.rac_valuesForKeyPath(keyPath, observer: target) }
github.com/AshFurrow/Swift-RAC-Macros
let signal = RACObserve(object, "number")
signal.subscribeNext { (number) -> Void in println("Received \(number)") }
Signal Operators
• Signal operators transform the values sent by signals
• These are func'ons on a signal that return a new signal
Map
• Mapping performs a value transforma'on on the given signal
• It “maps” each value sent along the signal to a new value
• It then passes that new value along, crea'ng a new signal
• This is the canonical value transforma'on
let signal = RACObserve(object, “number")
signal.map { (number) -> AnyObject! in return "\(number)" }.subscribeNext { (string) -> Void in println("Received \(string)") }
let signal = RACObserve(object, “person")
signal.map { (object) -> AnyObject! in return (object as Person).name }.subscribeNext { (name) -> Void in println(“name: \(name)") }
func toName(person: AnyObject!) -> AnyObject! { return (person as Person).name }
let signal = RACObserve(object, “person")
signal.map(toName).subscribeNext { (name) -> Void in println(“name: \(name)") }
Filter
• Filtering allows values that pass some test to “pass through”
someNumberSignal.filter { (object) -> Bool in return (object as NSNumber) > 5 }.subscribeNext { (object) -> Void in return "The number is \(object)" }
Bindings
• Bindings can bind a property to the latest value sent on a signal
• Bindings are typically created with the RAC func'on
• All bindings created with the RAC func'on are one-‐way
• Bindings are the secret sauce that hold apps together
public struct RAC { var target: NSObject var keyPath: String var nilValue: AnyObject? public init(_ target: NSObject, _ keyPath: String, nilValue: AnyObject? = nil) { self.target = target self.keyPath = keyPath self.nilValue = nilValue } func assignSignal(signal : RACSignal) -> RACDisposable { return signal.setKeyPath(self.keyPath, onObject: self.target, nilValue: self.nilValue) } }
infix operator <~ {} public func <~ (rac: RAC, signal: RACSignal) -> RACDisposable { return signal ~> rac }
public func ~> (signal: RACSignal, rac: RAC) -> RACDisposable { return rac.assignSignal(signal) }
github.com/AshFurrow/Swift-RAC-Macros
RAC(textField, "text") <~ RACObserve(self, "someString")
Derived State
• State is avoided in Reac'veCocoa, but is unavoidable in Cocoa
• Instead of hacky workarounds, we derive the state from signals
• Similar to the last example’s enabled state binding
Other Operators
• combineLatest()
• takeUn'l()
• scheduleOn()
• thro_le()
• not(), and(), or()
Getting Started
Getting Started
• Ge>ng started with Reac'veCocoa is easy
• Install Reac'veCocoa in your project as a submodule
• Switch to the swiG-‐development branch
Getting Started
• Start by replacing KVO methods with RACObserve
• Use subscribeNext() or doNext() for side-‐effects
• Start looking for opportuni'es to replace state with signals
Getting Started
• When create a property, ask yourself if a signal would be appropriate
• Is it important to know the value of the property aGer it’s set?
• Are side-‐effects performed when it’s changed?
Demo github.com/AshFurrow/MBLTDev
Demo
• No'ce subscribeNext: is used for side-‐effects
• Cocoa Touch isn’t built on FRP, so we need side-‐effects
• Network results are delivered on a background scheduler
• Use deliverOn() to reschedule them
github.com/artsy/eidolon
Eidolon• Completely open source iOS 8 SwiG app wri_en using Reac'veCocoa
• Lots of examples of its use
• Observing model proper'es
• User interface changes
• Networking code
• S'll a work-‐in-‐progress
Getting Started
• Start slowly
• You’re responsible for this decision
• Be prepared to answer ques'ons
• There is a community to support you
Wrap Up
1. Func'onal reac've programming uses a concept call “signals”
2. Reac'veCocoa uses signals to reduce mutable state
3. Ge>ng started is easy
@ashfurrow ashfurrow.com
Recommended