About me
Eliasz Sawicki
Blog: www.eliaszsawicki.com
Twitter: @EliSawic
@EliSawic
Introduction to
Functional Reactive
Programming
@EliSawic
Agenda
• What is Functional Reactive Programming?
• Let's take a look at ReactiveCocoa
• Working with streams
• Real life example
• Conclusion
@EliSawic
Functional Reactive
Programming
@EliSawic
Wikipedia
Functional reactive programming (FRP) is a programming
paradigm for reactive programming (asynchronous dataflow
programming) using the building blocks of functional
programming (e.g. map, reduce, filter).
@EliSawic
Reactive
Programming
@EliSawic
Asynchronous
Dataflow
@EliSawic
Reacting to state
changes
@EliSawic
Functional
Programming
@EliSawic
Immutable
@EliSawic
assert(f(x) == f(x))
@EliSawic
A person
class Person {
let name: String
let phoneNumber: String
init(name: String, phoneNumber: String) {
self.name = name
self.phoneNumber = phoneNumber
}
}
class MobilePhone {
func call(person: Person) -> Bool {
// implementation
}
}
@EliSawic
Mutable
let mobilePhone = MobilePhone()
let john = Person(name: "John", phoneNumber: "123456789")
func makeAPhoneCall(device: Phone, person: Person, countryCode: String) -> Bool {
person.phoneNumber = countryCode + person.phoneNumber
let success = device.call(person)
return success
}
makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // true
makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // false
makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // false
@EliSawic
Immutable
let mobilePhone = MobilePhone()
let john = Person(name: "John", phoneNumber: "123456789")
func makeAPhoneCall(device: Phone, person: Person, countryCode: String) -> Bool {
let prefixedPhoneNumber = countryCode + person.phoneNumber
let newPerson = Person(name: person.name, phoneNumber: prefixedPhoneNumber)
let success = device.call(newPerson)
return success
}
makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // true
makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // true
makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // true
@EliSawic
Stateless
@EliSawic
Stateful
var value = 0
func increment() -> Int {
value += 1
return value
}
@EliSawic
Stateless
func increment(value: Int) -> Int {
return value + 1
}
@EliSawic
Functional Reactive
Programming
@EliSawic
Imperative
vs
Declarative
@EliSawic
Imperative
@EliSawic
Imperative
let array = [0, 1, 2, 3, 4, 5]
var evenNumbers = [Int]()
for element in array {
if element % 2 == 0 {
evenNumbers.append(element)
}
}
@EliSawic
Declarative
@EliSawic
Declarative
let array = [0, 1, 2, 3, 4, 5]
let evenNumbers = array.filter { $0 % 2 == 0 }
@EliSawic
ReactiveCocoa
@EliSawic
Event streams
@EliSawic
Event Stream
@EliSawic
Event
@EliSawic
Non-Terminating
• Next
@EliSawic
Terminating
• Completed
• Failed
• Interrupted (Reactive Cocoa)
@EliSawic
Signal
@EliSawic
Events over time
@EliSawic
No side effects
@EliSawic
No random access to
events
@EliSawic
Must be observed in
order to access it's
events
@EliSawic
Hot
@EliSawic
Signal's lifetime
• Passes any number of Next events
• "Dies" when terminating event
• Any new observer will receive Interrupted event
@EliSawic
Observing
let someWork = Signal<Int, NoError> { observer in
observer.sendNext(1)
observer.sendNext(2)
....
observer.sendNext(1000000)
observer.sendCompleted()
}
signal.observe { (event) in
print(event)
}
signal.observeNext { (value) in
print(value)
}
signal.observeCompleted {
print("Completed")
}
@EliSawic
Pipe
@EliSawic
Pipe
let (signal, observer) = Signal<String, NoError>.pipe()
signal.observeNext({ text in
print(text)
})
signal.observeCompleted({
print("Test completed")
})
observer.sendNext("It's a test") // It's a test
observer.sendCompleted() // Test completed
@EliSawic
SignalProducer
@EliSawic
Represents tasks
@EliSawic
Creates signal
@EliSawic
Possible side effects
@EliSawic
Does not start it's
work if not started
@EliSawic
Cold
@EliSawic
Using Signal Producer
let producer = SignalProducer<String, NSError> { (observer, composite) in
observer.sendNext("In Progress...")
// ......
observer.sendCompleted()
}
producer.startWithSignal { (signal, _) in
signal.observeNext({ (text) in
print(text) // In Progress...
})
signal.observeCompleted({
print("Test completed") // Test completed
})
}
@EliSawic
Cold vs Hot
@EliSawic
Properties
@EliSawic
MutableProperty
let name = MutableProperty("Bob")
name.producer.startWithNext { (text) in
print(text)
}
name.value = "Lisa"
@EliSawic
Bindings
@EliSawic
Basic binding
let property = MutableProperty<String>("")
let (signal, _) = Signal<String, NoError>.pipe()
property <~ signal
@EliSawic
Schedulers
@EliSawic
Memory Management
@EliSawic
Disposables
@EliSawic
Manipulating signals
@EliSawic
Map
@EliSawic
Filter
@EliSawic
Aggregating
@EliSawic
Skip repeats
@EliSawic
Manipulating
multiple signals
@EliSawic
Combine latest
@EliSawic
Zip
@EliSawic
Merge
@EliSawic
Chaining operators
@EliSawic
Chain them all!
let newSignalX = signalX.skipRepeats()
.filter { x > 2 }
.map { x * 10 }
let newSignalY = signalY.filter { x > 10 }
let combined = combineLatest(newSignalX, newSignalY)
combined.observeNext { xValue, yValue in
print("Update: (xValue) : (yValue)")
}
@EliSawic
Example
@EliSawic
@EliSawic
@EliSawic
@EliSawic
@EliSawic
@EliSawic
How does it work?
@EliSawic
Is name valid?
let isValidName = nameSignal.map { (name) -> Bool in
return input.characters.count > 2
}
@EliSawic
Is mail valid?
let isValidMail = mailSignal.map { (mail) -> Bool in
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}"
let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
return emailTest.evaluateWithObject(mail)
}
@EliSawic
Combine Latest
let formData = combineLatest(isValidName,
isValidSurname,
isValidMail)
@EliSawic
Is form valid?
disposables += isFormValid <~ formData.map {
(isValidName, isValidSurname, isValidMail) -> Bool in
return isValidMail && isValidSurname && isValidMail
}
@EliSawic
Button state
let producer = isFormValid.producer.skipRepeats()
disposables += producer.startWithNext {[unowned self] (isValid) in
self.updateAcceptButtonWithState(isValid)
}
@EliSawic
Conclusion
@EliSawic
Thank you for your
attention!
@EliSawic

Introduction to Functional Reactive Programming