SlideShare a Scribd company logo
Building iOS apps
with ReactiveCocoa
About me
Eliasz Sawicki
Blog: http://eluss.github.io/
Twitter: @EliSawic
Let's begin
ReactiveCocoa
Functional Reactive
Programming
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).
Reactive
Programming
Reactive Programming
• Working with asynchronous dataflow
• Reacting to state changes
Functional
Programming
Functional Programming
• Immutable
assert(f(x) == f(x))
A person
class Person {
var name: String
init(name: String) {
self.name = name
}
}
Mutable
func personWithReversedName(person: Person) -> Person {
person.name = String(person.name.characters.reverse())
return person
}
let person = Person(name: "John")
let reversedA = personWithReversedName(person)
print(reversedA.name) // nhoJ
let reversedB = personWithReversedName(person)
print(reversedB.name) // John
Immutable
func personWithReversedName(person: Person) -> Person {
let name = String(person.name.characters.reverse())
let newPerson = Person(name: name)
return newPerson
}
let person = Person(name: "John")
let reversedA = personWithReversedName(person)
print(reversedA.name) // nhoJ
let reversedB = personWithReversedName(person)
print(reversedB.name) // nhoJ
Functional Programming
• Immutable
• Stateless
Stateful
var value = 0
func increment() {
value += 1
}
Stateless
func increment(value: Int) -> Int {
return value + 1
}
Declarative
Imperative
vs
Declarative
Imperative
let array = [0, 1, 2, 3, 4, 5]
var evenNumbers = [Int]()
for element in array {
if element % 2 == 0 {
evenNumbers.append(element)
}
}
Declarative
let array = [0, 1, 2, 3, 4, 5]
let evenNumbers = array.filter { $0 % 2 == 0 }
Back to
ReactiveCocoa
Event streams
Event Stream
Event
Non-Terminating
• Next
Terminating
• Completed
• Failed
• Interrupted
Observer
Signal
What is it?
• Represents events over time
• Must be observed in order to access it's events
• Observing a signal does not trigger any side effects (push
based)
• No random access to events
Signal's lifetime
• Passes any number of Next events
• "Dies" when terminating event arrives
• Any new observer will receive Interrupted event
Observing
signal.observe { (event) in
print(event)
}
signal.observeNext { (value) in
print(value)
}
signal.observeCompleter {
print("Completed")
}
Creating Signals
Basic signal
Signal<String, NSError> { (observer) -> Disposable? in
observer.sendNext("test")
observer.sendCompleted()
return ActionDisposable(action: {
print("Signal disposed")
})
}
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
SignalProducer
What is it?
• Represents tasks
• Creates signals
• Performs side effects
• Does not start it's work if not started
Injecting side effects
let producer = signalProducer
.on(started: {
print("Started")
}, event: { event in
print("Event: (event)")
}, failed: { error in
print("Failed: (error)")
}, completed: {
print("Completed")
}, interrupted: {
print("Interrupted")
}, terminated: {
print("Terminated")
}, disposed: {
print("Disposed")
}, next: { value in
print("Next: (value)")
})
Creating Signal
Producers
Basic Signal Producer
SignalProducer<String, NSError> { (observer, composite) in
composite.addDisposable({
print("Clearing work")
})
observer.sendNext("In Progres...")
observer.sendCompleted()
}
Buffer
let (producer, observer) = SignalProducer<String, NoError>.buffer(3)
observer.sendNext("test")
observer.sendCompleted()
producer.startWithSignal { (signal, disposable) in
signal.observeNext({ (text) in
print(text) // test
})
signal.observeCompleted({
print("Test completed") // Test completed
})
}
observer.sendNext("is interrupted")
observer.sendInterrupted()
producer.startWithSignal { (signal, disposable) in
signal.observeNext({ (text) in
print(text) // test, is interrupted
})
signal.observeInterrupted({
print("Test interrupted") // Test interrupted
})
}
Manipulating signals
Map
Map
let (numberSignal, observer) = Signal<Int, NoError>.pipe()
let textSignal = numberSignal.map { (number) -> String in
return "Number is (number)"
}
numberSignal.observeNext { (number) in
print(number) // 5
}
textSignal.observeNext { (text) in
print(text) // Number is 5
}
observer.sendNext(5)
Filter
Filter
let (numberSignal, observer) = Signal<Int, NoError>.pipe()
let fiveSignal = numberSignal.filter { (number) -> Bool in
return number == 5
}
numberSignal.observeNext { (number) in
print(number) // 6, 5
}
fiveSignal.observeNext { (number) in
print(number) // 5
}
observer.sendNext(6)
observer.sendNext(5)
Aggregating
Aggregating
let (numberSignal, observer) = Signal<Int, NoError>.pipe()
let aggregtingSignal = numberSignal.reduce(0) { (currentValue, addedValue) -> Int in
return currentValue + addedValue
}
numberSignal.observeNext { (number) in
print(number) // 5, 6
}
aggregtingSignal.observeNext { (number) in
print("Aggregated (number)") // Aggregated 11
}
observer.sendNext(5)
observer.sendNext(6)
observer.sendCompleted()
Skip repeats
Skip repeats
let (numberSignal, observer) = Signal<Int, NoError>.pipe()
numberSignal.observeNext { (number) in
print(number) // 1, 2, 2, 3
}
numberSignal.skipRepeats().observeNext { (number) in
print(number) // 1, 2, 3
}
observer.sendNext(1)
observer.sendNext(2)
observer.sendNext(2)
observer.sendNext(3)
Skip until
Skip until
let (numberSignal, observer) = Signal<Int, NoError>.pipe()
numberSignal.observeNext { (number) in
print(number) // 5, 6
}
let (trigger, triggerObserver) = Signal<Void, NoError>.pipe()
numberSignal.skipUntil(trigger).observeNext { (number) in
print("Triggered (number)") // Triggered 6
}
observer.sendNext(5)
triggerObserver.sendNext()
observer.sendNext(6)
Collect
let (numberSignal, observer) = Signal<Int, NoError>.pipe()
numberSignal.observeNext { (number) in
print(number) // 1, 2, 3, 4, 5
}
numberSignal.collect { (values) -> Bool in
return values.reduce(0, combine: +) > 4
}.observeNext { (values) in
print(values) // [1, 2, 3], [4 ,5]
}
observer.sendNext(1)
observer.sendNext(2)
observer.sendNext(3)
observer.sendNext(4)
observer.sendNext(5)
Manipulating
multiple signals
Combine latest
Combine latest
let (numberSignal, numberObserver) = Signal<Int, NoError>.pipe()
let (textSignal, textObserver) = Signal<String, NoError>.pipe()
combineLatest(numberSignal, textSignal).observeNext { (number, text) in
print("(text) - (number)")
}
numberObserver.sendNext(1) // Nothing printed
textObserver.sendNext("John") // John - 1
numberObserver.sendNext(2) // John - 2
textObserver.sendNext("Mary") // Mary - 2
Zip
Zip
let (menSignal, menObserver) = Signal<String, NoError>.pipe()
let (womenSignal, womenObserver) = Signal<String, NoError>.pipe()
let zippedSignal = zip(menSignal, womenSignal)
zippedSignal.observeNext { (man, woman) in
print("New couple - (man) and (woman)")
}
zippedSignal.observeCompleted({
print("Completed")
})
menObserver.sendNext("John") // Nothing printed
menObserver.sendNext("Tom") // Nothing printed
womenObserver.sendNext("Lisa") // New couple - John and Lisa
menObserver.sendNext("Greg") // Nothing printed
menObserver.sendCompleted()
womenObserver.sendNext("Sandra") // New couple - Tom and Sandra
womenObserver.sendNext("Mary") // New couple - Greg and Mary, Completed
Merge
Merge
let (menSignal, menObserver) = Signal<String, NoError>.pipe()
let (womenSignal, womenObserver) = Signal<String, NoError>.pipe()
let (peopleSignal, peopleObserver) = Signal<Signal<String, NoError>, NoError>.pipe()
peopleSignal.flatten(.Merge).observeNext { (name) in
print(name)
}
peopleObserver.sendNext(menSignal)
peopleObserver.sendNext(womenSignal)
menObserver.sendNext("John") // John
womenObserver.sendNext("Lisa") // Lisa
Handling errors
Catching errors
let (producer, observer) = SignalProducer<String, NSError>.buffer(5)
let error = NSError(domain: "domain", code: 0, userInfo: nil)
producer
.flatMapError { _ in SignalProducer<String, NoError>(value: "Default") }
.startWithNext { next in print(next) }
observer.sendNext("First") // prints "First"
observer.sendNext("Second") // prints "Second"
observer.sendFailed(error) // prints "Default"
Retry
var tries = 0 let limit = 2 let error = NSError(domain: "domain", code: 0, userInfo: nil)
let producer = SignalProducer<String, NSError> { (observer, _) in
if tries++ < limit {
observer.sendFailed(error)
} else {
observer.sendNext("Success")
observer.sendCompleted()
}
}
producer
.on(failed: {e in print("Failure")}).retry(2).start { event in // prints "Failure" twice
switch event {
case let .Next(next):
print(next) // prints "Success"
case let .Failed(error):
print("Failed: (error)")
}
}
Promoting
let (numbersSignal, numbersObserver) = Signal<Int, NoError>.pipe()
let (lettersSignal, lettersObserver) = Signal<String, NSError>.pipe()
numbersSignal
.promoteErrors(NSError)
.combineLatestWith(lettersSignal)
Mapping errors
Properties
Properties
• AnyProperty
• ConstantProperty
• MutableProperty
• DynamicProperty
MutableProperty
let name = MutableProperty<String>("Bob")
name.producer.startWithNext { (text) in
print(text)
}
name.modify { (name) -> String in
return name + "!"
}
name.value = "Lisa"
DynamicProperty
let textProperty = DynamicProperty(object: textField, keyPath: "text")
textProperty.producer.startWithNext { (text) in
print(text)
}
textProperty.value = "Textfield text"
Bindings
Basic binding
let property = MutableProperty<String>("")
let (producer, _) = SignalProducer<String, NoError>.buffer(1)
let (signal, _) = Signal<String, NoError>.pipe()
property <~ producer
property <~ signal
Action
Create Action
let action = Action<Int, String, NSError>({ (number) -> SignalProducer<String, NSError> in
return SignalProducer<String, NSError> {observer, disposable in
observer.sendNext("Number is (number)")
observer.sendCompleted()
}
})
Create signal producer
let producer = action.apply(1)
Execute action
prodcuer.startWithSignal { (signal, disposable ) in
signal.observeNext({ (value) in
print("(value)")
})
signal.observeFailed({ (actionError) in
print("(actionError)")
})
}
Observing actions
let action = Action<Int, String, NSError>({ (number) -> SignalProducer<String, NSError> in
return SignalProducer<String, NSError> {observer, disposable in
observer.sendNext("Number is (number)")
observer.sendCompleted()
}
})
action.values.observe { (value) in
print("Value: (value)")
}
action.errors.observe { (error) in
print("Error: (error)")
}
action.events.observe { (event) in
print("Event: (event)")
}
action.apply(5).startWithSignal { (_ , _ ) in }
CocoaAction
Prepare Action
var text = MutableProperty<String>("Switch is on")
let switchControl = UISwitch()
let switchAction = Action<Bool, String, NoError>({
(isOn) -> SignalProducer<String, NoError> in
return SignalProducer<String, NoError> { observer, disposable in
observer.sendNext(isOn ? "Switch is on" : "Switch is off")
observer.sendCompleted()
}
})
Create CocoaAction
let switchCocoaAction = CocoaAction(switchAction, { (control) -> Bool in
let control = control as! UISwitch
return control.on
})
switchControl.addTarget(switchCocoaAction, action: CocoaAction.selector,
forControlEvents: .ValueChanged)
text <~ switchAction.values
Schedulers
• SchedulerType
• ImmediateScheduler
• UIScheduler
• DateSchedulerType
• QueueScheduler
• TestScheduler
Memory Management
Disposables
Task
let producer = SignalProducer<String, NoError> { (observer, composite) in
let date = NSDate().dateByAddingTimeInterval(10)
composite += QueueScheduler().scheduleAfter(date, action: {
print("Doing my work") // Doing my work
observer.sendNext("Test")
observer.sendCompleted()
})
}
producer.startWithSignal { (signal, disposable) in
signal.observeNext({ (value) in
print(value) // Test
})
signal.observeCompleted({
print("Work completed") // Work completed
})
}
Cancelling work
let producer = SignalProducer<String, NoError> { (observer, composite) in
let date = NSDate().dateByAddingTimeInterval(10)
composite += QueueScheduler().scheduleAfter(date, action: {
print("Doing my work") // Not printed
observer.sendNext("Test")
observer.sendCompleted()
})
}
producer.startWithSignal { (signal, disposable) in
signal.observeNext({ (value) in
print(value) // Not printed
})
signal.observeInterrupted({
print("Work interrupted") // Work interrupted
})
let date = NSDate().dateByAddingTimeInterval(2)
QueueScheduler().scheduleAfter(date, action: {
disposable.dispose()
})
}
Cleaning
let producer = SignalProducer<String, NoError> { (observer, composite) in
composite.addDisposable({
print("I'm done")
})
let date = NSDate().dateByAddingTimeInterval(4)
composite += QueueScheduler().scheduleAfter(date, action: {
print("Doing my work") // Not printed
})
}
producer.startWithSignal { (signal, disposable) in
signal.observeInterrupted({
print("Work interrupted")
})
let date = NSDate().dateByAddingTimeInterval(2)
QueueScheduler().scheduleAfter(date, action: {
disposable.dispose() // Work interrupted, I'm done
})
}
Disposing signal
let producer = SignalProducer<String, NoError> { (observer, composite) in
composite.addDisposable({
print("I'm done")
})
let date = NSDate().dateByAddingTimeInterval(5)
composite += QueueScheduler().scheduleAfter(date, action: {
print("Doing my work") // Not printed
})
}
producer.startWithSignal { (signal, disposable) in
let signalDisposable = signal.observeInterrupted({
print("Work interrupted") // Not printed
})
let date = NSDate().dateByAddingTimeInterval(2)
QueueScheduler().scheduleAfter(date, action: {
signalDisposable!.dispose()
})
let date2 = NSDate().dateByAddingTimeInterval(4)
QueueScheduler().scheduleAfter(date2, action: {
disposable.dispose()
})
}
Closures
What's the result?
var value = 10
let closure = {
let date = NSDate().dateByAddingTimeInterval(2)
QueueScheduler().scheduleAfter(date, action: {
print(value)
})
}
closure()
value = 20
Captured value
var value = 10
let closure = { [value] in
let date = NSDate().dateByAddingTimeInterval(2)
QueueScheduler().scheduleAfter(date, action: {
print(value)
})
}
closure()
value = 20
Weak, Strong,
Unowned...
Unowned
let closure = { [unowned self] in
self.label.text = "test"
}
Weak
let closure = { [weak self] in
guard let weakSelf = self else { return }
self.label.text = "test"
}
Rex
UIButton
let cocoaAction = CocoaAction(action) { _ in }
//without Rex
button.addTarget(cocoaAction, action: CocoaAction.selector,
forControlEvents: .TouchUpInside)
//with Rex extensions
button.rex_pressed.value = cocoaAction
UITextField, UILabel, MutableProperty
var titleValue = MutableProperty<String?>(nil)
//without Rex
textField.rac_textSignal().subscribeNext {
self.titleValue.value = $0 as? String
}
titleValue.producer.startWithNext {
self.label.text = $0
self.label.hidden = $0?.characters.count < 5
}
//with Rex
titleValue <~ textField.rex_text
titleLabel.rex_text <~ titleValue
titleLabel.rex_hidden <~ titleValue.producer.map(
{ $0?.characters.count < 5 }
)
Let's see it in action

More Related Content

What's hot

Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2
José Paumard
 
Promise of an API
Promise of an APIPromise of an API
Promise of an API
Maxim Zaks
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1
José Paumard
 
C# Advanced L04-Threading
C# Advanced L04-ThreadingC# Advanced L04-Threading
C# Advanced L04-Threading
Mohammad Shaker
 
Akka.NET streams and reactive streams
Akka.NET streams and reactive streamsAkka.NET streams and reactive streams
Akka.NET streams and reactive streams
Bartosz Sypytkowski
 
Something about Golang
Something about GolangSomething about Golang
Something about Golang
Anton Arhipov
 
Rust
RustRust
Behind modern concurrency primitives
Behind modern concurrency primitivesBehind modern concurrency primitives
Behind modern concurrency primitives
Bartosz Sypytkowski
 
Rxjs vienna
Rxjs viennaRxjs vienna
Rxjs vienna
Christoffer Noring
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
Ignacio Martín
 
XpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp wayXpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp way
Giordano Scalzo
 
Angular2 rxjs
Angular2 rxjsAngular2 rxjs
Angular2 rxjs
Christoffer Noring
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин  (Avito)"Kotlin и rx в android" Дмитрий Воронин  (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)
AvitoTech
 
Java SE 8 for Java EE developers
Java SE 8 for Java EE developersJava SE 8 for Java EE developers
Java SE 8 for Java EE developers
José Paumard
 
Transition graph using free monads and existentials
Transition graph using free monads and existentialsTransition graph using free monads and existentials
Transition graph using free monads and existentials
Alexander Granin
 
JDK8 : parallel programming made (too ?) easy
JDK8 : parallel programming made (too ?) easyJDK8 : parallel programming made (too ?) easy
JDK8 : parallel programming made (too ?) easyJosé Paumard
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
Ignacio Martín
 
Functional Stream Processing with Scalaz-Stream
Functional Stream Processing with Scalaz-StreamFunctional Stream Processing with Scalaz-Stream
Functional Stream Processing with Scalaz-Stream
Adil Akhter
 

What's hot (20)

Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2
 
Promise of an API
Promise of an APIPromise of an API
Promise of an API
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1
 
Scala 2 + 2 > 4
Scala 2 + 2 > 4Scala 2 + 2 > 4
Scala 2 + 2 > 4
 
C# Advanced L04-Threading
C# Advanced L04-ThreadingC# Advanced L04-Threading
C# Advanced L04-Threading
 
Akka.NET streams and reactive streams
Akka.NET streams and reactive streamsAkka.NET streams and reactive streams
Akka.NET streams and reactive streams
 
Something about Golang
Something about GolangSomething about Golang
Something about Golang
 
Rust
RustRust
Rust
 
Behind modern concurrency primitives
Behind modern concurrency primitivesBehind modern concurrency primitives
Behind modern concurrency primitives
 
Rxjs ppt
Rxjs pptRxjs ppt
Rxjs ppt
 
Rxjs vienna
Rxjs viennaRxjs vienna
Rxjs vienna
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 
XpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp wayXpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp way
 
Angular2 rxjs
Angular2 rxjsAngular2 rxjs
Angular2 rxjs
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин  (Avito)"Kotlin и rx в android" Дмитрий Воронин  (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)
 
Java SE 8 for Java EE developers
Java SE 8 for Java EE developersJava SE 8 for Java EE developers
Java SE 8 for Java EE developers
 
Transition graph using free monads and existentials
Transition graph using free monads and existentialsTransition graph using free monads and existentials
Transition graph using free monads and existentials
 
JDK8 : parallel programming made (too ?) easy
JDK8 : parallel programming made (too ?) easyJDK8 : parallel programming made (too ?) easy
JDK8 : parallel programming made (too ?) easy
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
 
Functional Stream Processing with Scalaz-Stream
Functional Stream Processing with Scalaz-StreamFunctional Stream Processing with Scalaz-Stream
Functional Stream Processing with Scalaz-Stream
 

Viewers also liked

Impostor syndrome and individual competence - Jessica Rose - Codemotion Amste...
Impostor syndrome and individual competence - Jessica Rose - Codemotion Amste...Impostor syndrome and individual competence - Jessica Rose - Codemotion Amste...
Impostor syndrome and individual competence - Jessica Rose - Codemotion Amste...
Codemotion
 
Introduction to Angular js 2.0
Introduction to Angular js 2.0Introduction to Angular js 2.0
Introduction to Angular js 2.0
Nagaraju Sangam
 
Hola,hola
Hola,holaHola,hola
Hola,hola
gary vargas
 
Pintamania power
Pintamania powerPintamania power
Pintamania powerpituteam
 
Assignment four the presenter's fieldbook
Assignment four the presenter's fieldbookAssignment four the presenter's fieldbook
Assignment four the presenter's fieldbookjuniorvice04
 
Unidirectional Data Flow in Swift
Unidirectional Data Flow in SwiftUnidirectional Data Flow in Swift
Unidirectional Data Flow in Swift
Jason Larsen
 
An overview of JavaScript
An overview of JavaScriptAn overview of JavaScript
An overview of JavaScript
Poluru S
 
GTS Episode 1: Reactive programming in the wild
GTS Episode 1: Reactive programming in the wildGTS Episode 1: Reactive programming in the wild
GTS Episode 1: Reactive programming in the wild
Omer Iqbal
 
Reconsidering english language teaching in vernacular medium schools of india...
Reconsidering english language teaching in vernacular medium schools of india...Reconsidering english language teaching in vernacular medium schools of india...
Reconsidering english language teaching in vernacular medium schools of india...
Atiya Khan
 
ENJ-1-337 Presentación Módulo II Delitos Electrónicos (2)
ENJ-1-337 Presentación Módulo II Delitos Electrónicos (2)ENJ-1-337 Presentación Módulo II Delitos Electrónicos (2)
ENJ-1-337 Presentación Módulo II Delitos Electrónicos (2)
ENJ
 
Hybrid mobile and Ionic
Hybrid mobile and IonicHybrid mobile and Ionic
Hybrid mobile and Ionic
Liju Pillai
 
Higher order infrastructure: from Docker basics to cluster management - Nicol...
Higher order infrastructure: from Docker basics to cluster management - Nicol...Higher order infrastructure: from Docker basics to cluster management - Nicol...
Higher order infrastructure: from Docker basics to cluster management - Nicol...
Codemotion
 
Introduction to Functional Reactive Programming
Introduction to Functional Reactive ProgrammingIntroduction to Functional Reactive Programming
Introduction to Functional Reactive Programming
Đặng Thái Sơn
 
Hybrid vs native mobile development – how to choose a tech stack
Hybrid vs native mobile development – how to choose a tech stackHybrid vs native mobile development – how to choose a tech stack
Hybrid vs native mobile development – how to choose a tech stack
Jacques De Vos
 
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without CompromisesIonic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises
Jacob Friesen
 
La Magia de Disney, presentación René Carrasco
La Magia de Disney, presentación René CarrascoLa Magia de Disney, presentación René Carrasco
La Magia de Disney, presentación René Carrasco
SMCMX TURISMO
 
Кластер БГУИР: расширенные возможности
Кластер БГУИР: расширенные возможностиКластер БГУИР: расширенные возможности
Кластер БГУИР: расширенные возможности
Alexey Demidchuk
 

Viewers also liked (19)

Impostor syndrome and individual competence - Jessica Rose - Codemotion Amste...
Impostor syndrome and individual competence - Jessica Rose - Codemotion Amste...Impostor syndrome and individual competence - Jessica Rose - Codemotion Amste...
Impostor syndrome and individual competence - Jessica Rose - Codemotion Amste...
 
Introduction to Angular js 2.0
Introduction to Angular js 2.0Introduction to Angular js 2.0
Introduction to Angular js 2.0
 
Hola,hola
Hola,holaHola,hola
Hola,hola
 
Pintamania power
Pintamania powerPintamania power
Pintamania power
 
Abduallazeez CV
Abduallazeez CVAbduallazeez CV
Abduallazeez CV
 
Jessica fox
Jessica foxJessica fox
Jessica fox
 
Assignment four the presenter's fieldbook
Assignment four the presenter's fieldbookAssignment four the presenter's fieldbook
Assignment four the presenter's fieldbook
 
Unidirectional Data Flow in Swift
Unidirectional Data Flow in SwiftUnidirectional Data Flow in Swift
Unidirectional Data Flow in Swift
 
An overview of JavaScript
An overview of JavaScriptAn overview of JavaScript
An overview of JavaScript
 
GTS Episode 1: Reactive programming in the wild
GTS Episode 1: Reactive programming in the wildGTS Episode 1: Reactive programming in the wild
GTS Episode 1: Reactive programming in the wild
 
Reconsidering english language teaching in vernacular medium schools of india...
Reconsidering english language teaching in vernacular medium schools of india...Reconsidering english language teaching in vernacular medium schools of india...
Reconsidering english language teaching in vernacular medium schools of india...
 
ENJ-1-337 Presentación Módulo II Delitos Electrónicos (2)
ENJ-1-337 Presentación Módulo II Delitos Electrónicos (2)ENJ-1-337 Presentación Módulo II Delitos Electrónicos (2)
ENJ-1-337 Presentación Módulo II Delitos Electrónicos (2)
 
Hybrid mobile and Ionic
Hybrid mobile and IonicHybrid mobile and Ionic
Hybrid mobile and Ionic
 
Higher order infrastructure: from Docker basics to cluster management - Nicol...
Higher order infrastructure: from Docker basics to cluster management - Nicol...Higher order infrastructure: from Docker basics to cluster management - Nicol...
Higher order infrastructure: from Docker basics to cluster management - Nicol...
 
Introduction to Functional Reactive Programming
Introduction to Functional Reactive ProgrammingIntroduction to Functional Reactive Programming
Introduction to Functional Reactive Programming
 
Hybrid vs native mobile development – how to choose a tech stack
Hybrid vs native mobile development – how to choose a tech stackHybrid vs native mobile development – how to choose a tech stack
Hybrid vs native mobile development – how to choose a tech stack
 
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without CompromisesIonic Mobile Applications - Hybrid Mobile Applications Without Compromises
Ionic Mobile Applications - Hybrid Mobile Applications Without Compromises
 
La Magia de Disney, presentación René Carrasco
La Magia de Disney, presentación René CarrascoLa Magia de Disney, presentación René Carrasco
La Magia de Disney, presentación René Carrasco
 
Кластер БГУИР: расширенные возможности
Кластер БГУИР: расширенные возможностиКластер БГУИР: расширенные возможности
Кластер БГУИР: расширенные возможности
 

Similar to ReactiveCocoa workshop

Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
Tor Ivry
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
Adam L Barrett
 
Geeks Anonymes - Le langage Go
Geeks Anonymes - Le langage GoGeeks Anonymes - Le langage Go
Geeks Anonymes - Le langage Go
Geeks Anonymes
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
Aleksandar Prokopec
 
golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptx
Guy Komari
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
Prashant Kalkar
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
Introduction to go
Introduction to goIntroduction to go
Introduction to go
Jaehue Jang
 
Столпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай Мозговой
Sigma Software
 
Swift 5.1 Language Guide Notes.pdf
Swift 5.1 Language Guide Notes.pdfSwift 5.1 Language Guide Notes.pdf
Swift 5.1 Language Guide Notes.pdf
JkPoppy
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on Android
Tomáš Kypta
 
オープンデータを使ったモバイルアプリ開発(応用編)
オープンデータを使ったモバイルアプリ開発(応用編)オープンデータを使ったモバイルアプリ開発(応用編)
オープンデータを使ったモバイルアプリ開発(応用編)
Takayuki Goto
 
III MCS python lab (1).pdf
III MCS python lab (1).pdfIII MCS python lab (1).pdf
III MCS python lab (1).pdf
srxerox
 
Reactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftReactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwift
Florent Pillet
 
関数潮流(Function Tendency)
関数潮流(Function Tendency)関数潮流(Function Tendency)
関数潮流(Function Tendency)riue
 
81818088 isc-class-xii-computer-science-project-java-programs
81818088 isc-class-xii-computer-science-project-java-programs81818088 isc-class-xii-computer-science-project-java-programs
81818088 isc-class-xii-computer-science-project-java-programsAbhishek Jena
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
Pavlo Baron
 
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemWprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Sages
 
What's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritageWhat's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritage
DroidConTLV
 

Similar to ReactiveCocoa workshop (20)

ProgrammingwithGOLang
ProgrammingwithGOLangProgrammingwithGOLang
ProgrammingwithGOLang
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
Geeks Anonymes - Le langage Go
Geeks Anonymes - Le langage GoGeeks Anonymes - Le langage Go
Geeks Anonymes - Le langage Go
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
golang_getting_started.pptx
golang_getting_started.pptxgolang_getting_started.pptx
golang_getting_started.pptx
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
Introduction to go
Introduction to goIntroduction to go
Introduction to go
 
Столпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай МозговойСтолпы функционального программирования для адептов ООП, Николай Мозговой
Столпы функционального программирования для адептов ООП, Николай Мозговой
 
Swift 5.1 Language Guide Notes.pdf
Swift 5.1 Language Guide Notes.pdfSwift 5.1 Language Guide Notes.pdf
Swift 5.1 Language Guide Notes.pdf
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on Android
 
オープンデータを使ったモバイルアプリ開発(応用編)
オープンデータを使ったモバイルアプリ開発(応用編)オープンデータを使ったモバイルアプリ開発(応用編)
オープンデータを使ったモバイルアプリ開発(応用編)
 
III MCS python lab (1).pdf
III MCS python lab (1).pdfIII MCS python lab (1).pdf
III MCS python lab (1).pdf
 
Reactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwiftReactive Programming Patterns with RxSwift
Reactive Programming Patterns with RxSwift
 
関数潮流(Function Tendency)
関数潮流(Function Tendency)関数潮流(Function Tendency)
関数潮流(Function Tendency)
 
81818088 isc-class-xii-computer-science-project-java-programs
81818088 isc-class-xii-computer-science-project-java-programs81818088 isc-class-xii-computer-science-project-java-programs
81818088 isc-class-xii-computer-science-project-java-programs
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
 
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemWprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
 
What's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritageWhat's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritage
 

More from Eliasz Sawicki

Redux - 4Developers
Redux - 4DevelopersRedux - 4Developers
Redux - 4Developers
Eliasz Sawicki
 
Eliasz sawickimeetupit
Eliasz sawickimeetupitEliasz sawickimeetupit
Eliasz sawickimeetupit
Eliasz Sawicki
 
Developing more in less time
Developing more in less timeDeveloping more in less time
Developing more in less time
Eliasz Sawicki
 
The art-of-developing-more-in-less-time-berlin
The art-of-developing-more-in-less-time-berlinThe art-of-developing-more-in-less-time-berlin
The art-of-developing-more-in-less-time-berlin
Eliasz Sawicki
 
Tech fest
Tech festTech fest
Tech fest
Eliasz Sawicki
 
Introduction to react native
Introduction to react nativeIntroduction to react native
Introduction to react native
Eliasz Sawicki
 
Doing more in less time - Mobiconf
Doing more in less time - MobiconfDoing more in less time - Mobiconf
Doing more in less time - Mobiconf
Eliasz Sawicki
 
iOSCon
iOSConiOSCon
Code europe
Code europeCode europe
Code europe
Eliasz Sawicki
 
Introduction To Functional Reactive Programming Poznan
Introduction To Functional Reactive Programming PoznanIntroduction To Functional Reactive Programming Poznan
Introduction To Functional Reactive Programming Poznan
Eliasz Sawicki
 
Introduction to Functional Reactive Programming
Introduction to Functional Reactive ProgrammingIntroduction to Functional Reactive Programming
Introduction to Functional Reactive Programming
Eliasz Sawicki
 
Time traveling with ReSwift
Time traveling with ReSwiftTime traveling with ReSwift
Time traveling with ReSwift
Eliasz Sawicki
 
Calabash
CalabashCalabash
Calabash
Eliasz Sawicki
 
ReSwift CocoaHeads Tricity
ReSwift CocoaHeads TricityReSwift CocoaHeads Tricity
ReSwift CocoaHeads Tricity
Eliasz Sawicki
 

More from Eliasz Sawicki (14)

Redux - 4Developers
Redux - 4DevelopersRedux - 4Developers
Redux - 4Developers
 
Eliasz sawickimeetupit
Eliasz sawickimeetupitEliasz sawickimeetupit
Eliasz sawickimeetupit
 
Developing more in less time
Developing more in less timeDeveloping more in less time
Developing more in less time
 
The art-of-developing-more-in-less-time-berlin
The art-of-developing-more-in-less-time-berlinThe art-of-developing-more-in-less-time-berlin
The art-of-developing-more-in-less-time-berlin
 
Tech fest
Tech festTech fest
Tech fest
 
Introduction to react native
Introduction to react nativeIntroduction to react native
Introduction to react native
 
Doing more in less time - Mobiconf
Doing more in less time - MobiconfDoing more in less time - Mobiconf
Doing more in less time - Mobiconf
 
iOSCon
iOSConiOSCon
iOSCon
 
Code europe
Code europeCode europe
Code europe
 
Introduction To Functional Reactive Programming Poznan
Introduction To Functional Reactive Programming PoznanIntroduction To Functional Reactive Programming Poznan
Introduction To Functional Reactive Programming Poznan
 
Introduction to Functional Reactive Programming
Introduction to Functional Reactive ProgrammingIntroduction to Functional Reactive Programming
Introduction to Functional Reactive Programming
 
Time traveling with ReSwift
Time traveling with ReSwiftTime traveling with ReSwift
Time traveling with ReSwift
 
Calabash
CalabashCalabash
Calabash
 
ReSwift CocoaHeads Tricity
ReSwift CocoaHeads TricityReSwift CocoaHeads Tricity
ReSwift CocoaHeads Tricity
 

Recently uploaded

The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
Quantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIsQuantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIs
Vlad Stirbu
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
UiPathCommunity
 
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptxSecstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
nkrafacyberclub
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
RinaMondal9
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
Peter Spielvogel
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 

Recently uploaded (20)

The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Quantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIsQuantum Computing: Current Landscape and the Future Role of APIs
Quantum Computing: Current Landscape and the Future Role of APIs
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
Le nuove frontiere dell'AI nell'RPA con UiPath Autopilot™
 
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptxSecstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
Assure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyesAssure Contact Center Experiences for Your Customers With ThousandEyes
Assure Contact Center Experiences for Your Customers With ThousandEyes
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 

ReactiveCocoa workshop

  • 1. Building iOS apps with ReactiveCocoa
  • 2. About me Eliasz Sawicki Blog: http://eluss.github.io/ Twitter: @EliSawic
  • 6. 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).
  • 8. Reactive Programming • Working with asynchronous dataflow • Reacting to state changes
  • 12. A person class Person { var name: String init(name: String) { self.name = name } }
  • 13. Mutable func personWithReversedName(person: Person) -> Person { person.name = String(person.name.characters.reverse()) return person } let person = Person(name: "John") let reversedA = personWithReversedName(person) print(reversedA.name) // nhoJ let reversedB = personWithReversedName(person) print(reversedB.name) // John
  • 14. Immutable func personWithReversedName(person: Person) -> Person { let name = String(person.name.characters.reverse()) let newPerson = Person(name: name) return newPerson } let person = Person(name: "John") let reversedA = personWithReversedName(person) print(reversedA.name) // nhoJ let reversedB = personWithReversedName(person) print(reversedB.name) // nhoJ
  • 16. Stateful var value = 0 func increment() { value += 1 }
  • 17. Stateless func increment(value: Int) -> Int { return value + 1 }
  • 20. Imperative let array = [0, 1, 2, 3, 4, 5] var evenNumbers = [Int]() for element in array { if element % 2 == 0 { evenNumbers.append(element) } }
  • 21. Declarative let array = [0, 1, 2, 3, 4, 5] let evenNumbers = array.filter { $0 % 2 == 0 }
  • 25. Event
  • 29. What is it? • Represents events over time • Must be observed in order to access it's events • Observing a signal does not trigger any side effects (push based) • No random access to events
  • 30. Signal's lifetime • Passes any number of Next events • "Dies" when terminating event arrives • Any new observer will receive Interrupted event
  • 31. Observing signal.observe { (event) in print(event) } signal.observeNext { (value) in print(value) } signal.observeCompleter { print("Completed") }
  • 33. Basic signal Signal<String, NSError> { (observer) -> Disposable? in observer.sendNext("test") observer.sendCompleted() return ActionDisposable(action: { print("Signal disposed") }) }
  • 34. Pipe
  • 35. 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
  • 37. What is it? • Represents tasks • Creates signals • Performs side effects • Does not start it's work if not started
  • 38. Injecting side effects let producer = signalProducer .on(started: { print("Started") }, event: { event in print("Event: (event)") }, failed: { error in print("Failed: (error)") }, completed: { print("Completed") }, interrupted: { print("Interrupted") }, terminated: { print("Terminated") }, disposed: { print("Disposed") }, next: { value in print("Next: (value)") })
  • 40. Basic Signal Producer SignalProducer<String, NSError> { (observer, composite) in composite.addDisposable({ print("Clearing work") }) observer.sendNext("In Progres...") observer.sendCompleted() }
  • 41. Buffer let (producer, observer) = SignalProducer<String, NoError>.buffer(3) observer.sendNext("test") observer.sendCompleted() producer.startWithSignal { (signal, disposable) in signal.observeNext({ (text) in print(text) // test }) signal.observeCompleted({ print("Test completed") // Test completed }) } observer.sendNext("is interrupted") observer.sendInterrupted() producer.startWithSignal { (signal, disposable) in signal.observeNext({ (text) in print(text) // test, is interrupted }) signal.observeInterrupted({ print("Test interrupted") // Test interrupted }) }
  • 43. Map
  • 44. Map let (numberSignal, observer) = Signal<Int, NoError>.pipe() let textSignal = numberSignal.map { (number) -> String in return "Number is (number)" } numberSignal.observeNext { (number) in print(number) // 5 } textSignal.observeNext { (text) in print(text) // Number is 5 } observer.sendNext(5)
  • 46. Filter let (numberSignal, observer) = Signal<Int, NoError>.pipe() let fiveSignal = numberSignal.filter { (number) -> Bool in return number == 5 } numberSignal.observeNext { (number) in print(number) // 6, 5 } fiveSignal.observeNext { (number) in print(number) // 5 } observer.sendNext(6) observer.sendNext(5)
  • 48. Aggregating let (numberSignal, observer) = Signal<Int, NoError>.pipe() let aggregtingSignal = numberSignal.reduce(0) { (currentValue, addedValue) -> Int in return currentValue + addedValue } numberSignal.observeNext { (number) in print(number) // 5, 6 } aggregtingSignal.observeNext { (number) in print("Aggregated (number)") // Aggregated 11 } observer.sendNext(5) observer.sendNext(6) observer.sendCompleted()
  • 50. Skip repeats let (numberSignal, observer) = Signal<Int, NoError>.pipe() numberSignal.observeNext { (number) in print(number) // 1, 2, 2, 3 } numberSignal.skipRepeats().observeNext { (number) in print(number) // 1, 2, 3 } observer.sendNext(1) observer.sendNext(2) observer.sendNext(2) observer.sendNext(3)
  • 52. Skip until let (numberSignal, observer) = Signal<Int, NoError>.pipe() numberSignal.observeNext { (number) in print(number) // 5, 6 } let (trigger, triggerObserver) = Signal<Void, NoError>.pipe() numberSignal.skipUntil(trigger).observeNext { (number) in print("Triggered (number)") // Triggered 6 } observer.sendNext(5) triggerObserver.sendNext() observer.sendNext(6)
  • 53. Collect let (numberSignal, observer) = Signal<Int, NoError>.pipe() numberSignal.observeNext { (number) in print(number) // 1, 2, 3, 4, 5 } numberSignal.collect { (values) -> Bool in return values.reduce(0, combine: +) > 4 }.observeNext { (values) in print(values) // [1, 2, 3], [4 ,5] } observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) observer.sendNext(4) observer.sendNext(5)
  • 57. let (numberSignal, numberObserver) = Signal<Int, NoError>.pipe() let (textSignal, textObserver) = Signal<String, NoError>.pipe() combineLatest(numberSignal, textSignal).observeNext { (number, text) in print("(text) - (number)") } numberObserver.sendNext(1) // Nothing printed textObserver.sendNext("John") // John - 1 numberObserver.sendNext(2) // John - 2 textObserver.sendNext("Mary") // Mary - 2
  • 58. Zip
  • 59. Zip let (menSignal, menObserver) = Signal<String, NoError>.pipe() let (womenSignal, womenObserver) = Signal<String, NoError>.pipe() let zippedSignal = zip(menSignal, womenSignal) zippedSignal.observeNext { (man, woman) in print("New couple - (man) and (woman)") } zippedSignal.observeCompleted({ print("Completed") }) menObserver.sendNext("John") // Nothing printed menObserver.sendNext("Tom") // Nothing printed womenObserver.sendNext("Lisa") // New couple - John and Lisa menObserver.sendNext("Greg") // Nothing printed menObserver.sendCompleted() womenObserver.sendNext("Sandra") // New couple - Tom and Sandra womenObserver.sendNext("Mary") // New couple - Greg and Mary, Completed
  • 60. Merge
  • 61. Merge let (menSignal, menObserver) = Signal<String, NoError>.pipe() let (womenSignal, womenObserver) = Signal<String, NoError>.pipe() let (peopleSignal, peopleObserver) = Signal<Signal<String, NoError>, NoError>.pipe() peopleSignal.flatten(.Merge).observeNext { (name) in print(name) } peopleObserver.sendNext(menSignal) peopleObserver.sendNext(womenSignal) menObserver.sendNext("John") // John womenObserver.sendNext("Lisa") // Lisa
  • 63. Catching errors let (producer, observer) = SignalProducer<String, NSError>.buffer(5) let error = NSError(domain: "domain", code: 0, userInfo: nil) producer .flatMapError { _ in SignalProducer<String, NoError>(value: "Default") } .startWithNext { next in print(next) } observer.sendNext("First") // prints "First" observer.sendNext("Second") // prints "Second" observer.sendFailed(error) // prints "Default"
  • 64. Retry var tries = 0 let limit = 2 let error = NSError(domain: "domain", code: 0, userInfo: nil) let producer = SignalProducer<String, NSError> { (observer, _) in if tries++ < limit { observer.sendFailed(error) } else { observer.sendNext("Success") observer.sendCompleted() } } producer .on(failed: {e in print("Failure")}).retry(2).start { event in // prints "Failure" twice switch event { case let .Next(next): print(next) // prints "Success" case let .Failed(error): print("Failed: (error)") } }
  • 65. Promoting let (numbersSignal, numbersObserver) = Signal<Int, NoError>.pipe() let (lettersSignal, lettersObserver) = Signal<String, NSError>.pipe() numbersSignal .promoteErrors(NSError) .combineLatestWith(lettersSignal)
  • 68. Properties • AnyProperty • ConstantProperty • MutableProperty • DynamicProperty
  • 69. MutableProperty let name = MutableProperty<String>("Bob") name.producer.startWithNext { (text) in print(text) } name.modify { (name) -> String in return name + "!" } name.value = "Lisa"
  • 70. DynamicProperty let textProperty = DynamicProperty(object: textField, keyPath: "text") textProperty.producer.startWithNext { (text) in print(text) } textProperty.value = "Textfield text"
  • 72. Basic binding let property = MutableProperty<String>("") let (producer, _) = SignalProducer<String, NoError>.buffer(1) let (signal, _) = Signal<String, NoError>.pipe() property <~ producer property <~ signal
  • 74. Create Action let action = Action<Int, String, NSError>({ (number) -> SignalProducer<String, NSError> in return SignalProducer<String, NSError> {observer, disposable in observer.sendNext("Number is (number)") observer.sendCompleted() } })
  • 75. Create signal producer let producer = action.apply(1)
  • 76. Execute action prodcuer.startWithSignal { (signal, disposable ) in signal.observeNext({ (value) in print("(value)") }) signal.observeFailed({ (actionError) in print("(actionError)") }) }
  • 77. Observing actions let action = Action<Int, String, NSError>({ (number) -> SignalProducer<String, NSError> in return SignalProducer<String, NSError> {observer, disposable in observer.sendNext("Number is (number)") observer.sendCompleted() } }) action.values.observe { (value) in print("Value: (value)") } action.errors.observe { (error) in print("Error: (error)") } action.events.observe { (event) in print("Event: (event)") } action.apply(5).startWithSignal { (_ , _ ) in }
  • 79. Prepare Action var text = MutableProperty<String>("Switch is on") let switchControl = UISwitch() let switchAction = Action<Bool, String, NoError>({ (isOn) -> SignalProducer<String, NoError> in return SignalProducer<String, NoError> { observer, disposable in observer.sendNext(isOn ? "Switch is on" : "Switch is off") observer.sendCompleted() } })
  • 80. Create CocoaAction let switchCocoaAction = CocoaAction(switchAction, { (control) -> Bool in let control = control as! UISwitch return control.on }) switchControl.addTarget(switchCocoaAction, action: CocoaAction.selector, forControlEvents: .ValueChanged) text <~ switchAction.values
  • 81. Schedulers • SchedulerType • ImmediateScheduler • UIScheduler • DateSchedulerType • QueueScheduler • TestScheduler
  • 84. Task let producer = SignalProducer<String, NoError> { (observer, composite) in let date = NSDate().dateByAddingTimeInterval(10) composite += QueueScheduler().scheduleAfter(date, action: { print("Doing my work") // Doing my work observer.sendNext("Test") observer.sendCompleted() }) } producer.startWithSignal { (signal, disposable) in signal.observeNext({ (value) in print(value) // Test }) signal.observeCompleted({ print("Work completed") // Work completed }) }
  • 85. Cancelling work let producer = SignalProducer<String, NoError> { (observer, composite) in let date = NSDate().dateByAddingTimeInterval(10) composite += QueueScheduler().scheduleAfter(date, action: { print("Doing my work") // Not printed observer.sendNext("Test") observer.sendCompleted() }) } producer.startWithSignal { (signal, disposable) in signal.observeNext({ (value) in print(value) // Not printed }) signal.observeInterrupted({ print("Work interrupted") // Work interrupted }) let date = NSDate().dateByAddingTimeInterval(2) QueueScheduler().scheduleAfter(date, action: { disposable.dispose() }) }
  • 86. Cleaning let producer = SignalProducer<String, NoError> { (observer, composite) in composite.addDisposable({ print("I'm done") }) let date = NSDate().dateByAddingTimeInterval(4) composite += QueueScheduler().scheduleAfter(date, action: { print("Doing my work") // Not printed }) } producer.startWithSignal { (signal, disposable) in signal.observeInterrupted({ print("Work interrupted") }) let date = NSDate().dateByAddingTimeInterval(2) QueueScheduler().scheduleAfter(date, action: { disposable.dispose() // Work interrupted, I'm done }) }
  • 87. Disposing signal let producer = SignalProducer<String, NoError> { (observer, composite) in composite.addDisposable({ print("I'm done") }) let date = NSDate().dateByAddingTimeInterval(5) composite += QueueScheduler().scheduleAfter(date, action: { print("Doing my work") // Not printed }) } producer.startWithSignal { (signal, disposable) in let signalDisposable = signal.observeInterrupted({ print("Work interrupted") // Not printed }) let date = NSDate().dateByAddingTimeInterval(2) QueueScheduler().scheduleAfter(date, action: { signalDisposable!.dispose() }) let date2 = NSDate().dateByAddingTimeInterval(4) QueueScheduler().scheduleAfter(date2, action: { disposable.dispose() }) }
  • 89. What's the result? var value = 10 let closure = { let date = NSDate().dateByAddingTimeInterval(2) QueueScheduler().scheduleAfter(date, action: { print(value) }) } closure() value = 20
  • 90. Captured value var value = 10 let closure = { [value] in let date = NSDate().dateByAddingTimeInterval(2) QueueScheduler().scheduleAfter(date, action: { print(value) }) } closure() value = 20
  • 92. Unowned let closure = { [unowned self] in self.label.text = "test" }
  • 93. Weak let closure = { [weak self] in guard let weakSelf = self else { return } self.label.text = "test" }
  • 94. Rex
  • 95. UIButton let cocoaAction = CocoaAction(action) { _ in } //without Rex button.addTarget(cocoaAction, action: CocoaAction.selector, forControlEvents: .TouchUpInside) //with Rex extensions button.rex_pressed.value = cocoaAction
  • 96. UITextField, UILabel, MutableProperty var titleValue = MutableProperty<String?>(nil) //without Rex textField.rac_textSignal().subscribeNext { self.titleValue.value = $0 as? String } titleValue.producer.startWithNext { self.label.text = $0 self.label.hidden = $0?.characters.count < 5 } //with Rex titleValue <~ textField.rex_text titleLabel.rex_text <~ titleValue titleLabel.rex_hidden <~ titleValue.producer.map( { $0?.characters.count < 5 } )
  • 97. Let's see it in action