reactivecocoa workshop
TRANSCRIPT
![Page 1: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/1.jpg)
Building iOS apps with ReactiveCocoa
![Page 2: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/2.jpg)
About me
Eliasz SawickiBlog: http://eluss.github.io/Twitter: @EliSawic
![Page 3: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/3.jpg)
Let's begin
![Page 4: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/4.jpg)
ReactiveCocoa
![Page 5: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/5.jpg)
Functional Reactive Programming
![Page 6: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/6.jpg)
WikipediaFunctional 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).
![Page 7: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/7.jpg)
Reactive Programming
![Page 8: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/8.jpg)
Reactive Programming• Working with asynchronous dataflow
• Reacting to state changes
![Page 9: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/9.jpg)
Functional Programming
![Page 10: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/10.jpg)
Functional Programming• Immutable
![Page 11: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/11.jpg)
assert(f(x) == f(x))
![Page 12: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/12.jpg)
A personclass Person { var name: String init(name: String) { self.name = name }}
![Page 13: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/13.jpg)
Mutablefunc 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) // nhoJlet reversedB = personWithReversedName(person)print(reversedB.name) // John
![Page 14: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/14.jpg)
Immutablefunc 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) // nhoJlet reversedB = personWithReversedName(person)print(reversedB.name) // nhoJ
![Page 15: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/15.jpg)
Functional Programming• Immutable• Stateless
![Page 16: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/16.jpg)
Statefulvar value = 0
func increment() { value += 1}
![Page 17: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/17.jpg)
Statelessfunc increment(value: Int) -> Int { return value + 1}
![Page 18: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/18.jpg)
Declarative
![Page 19: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/19.jpg)
Imperative vs
Declarative
![Page 20: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/20.jpg)
Imperativelet array = [0, 1, 2, 3, 4, 5]var evenNumbers = [Int]()for element in array { if element % 2 == 0 { evenNumbers.append(element) }}
![Page 21: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/21.jpg)
Declarativelet array = [0, 1, 2, 3, 4, 5]let evenNumbers = array.filter { $0 % 2 == 0 }
![Page 22: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/22.jpg)
Back to ReactiveCocoa
![Page 23: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/23.jpg)
Event streams
![Page 24: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/24.jpg)
Event Stream
![Page 25: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/25.jpg)
Event
![Page 26: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/26.jpg)
Non-Terminating
• Next
Terminating
• Completed
• Failed
• Interrupted
![Page 27: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/27.jpg)
Observer
![Page 28: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/28.jpg)
Signal
![Page 29: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/29.jpg)
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
![Page 30: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/30.jpg)
Signal's lifetime• Passes any number of Next events
• "Dies" when terminating event arrives
• Any new observer will receive Interrupted event
![Page 31: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/31.jpg)
Observingsignal.observe { (event) in print(event)}signal.observeNext { (value) in print(value)}
signal.observeCompleter { print("Completed")}
![Page 32: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/32.jpg)
Creating Signals
![Page 33: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/33.jpg)
Basic signalSignal<String, NSError> { (observer) -> Disposable? in observer.sendNext("test") observer.sendCompleted() return ActionDisposable(action: { print("Signal disposed") })}
![Page 34: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/34.jpg)
Pipe
![Page 35: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/35.jpg)
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 testobserver.sendCompleted() // Test completed
![Page 36: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/36.jpg)
SignalProducer
![Page 37: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/37.jpg)
What is it?• Represents tasks
• Creates signals
• Performs side effects
• Does not start it's work if not started
![Page 38: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/38.jpg)
Injecting side effectslet 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)") })
![Page 39: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/39.jpg)
Creating Signal Producers
![Page 40: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/40.jpg)
Basic Signal ProducerSignalProducer<String, NSError> { (observer, composite) in composite.addDisposable({ print("Clearing work") })
observer.sendNext("In Progres...") observer.sendCompleted()}
![Page 41: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/41.jpg)
Bufferlet (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 })}
![Page 42: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/42.jpg)
Manipulating signals
![Page 43: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/43.jpg)
Map
![Page 44: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/44.jpg)
Maplet (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)
![Page 45: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/45.jpg)
Filter
![Page 46: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/46.jpg)
Filterlet (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)
![Page 47: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/47.jpg)
Aggregating
![Page 48: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/48.jpg)
Aggregatinglet (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()
![Page 49: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/49.jpg)
Skip repeats
![Page 50: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/50.jpg)
Skip repeatslet (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)
![Page 51: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/51.jpg)
Skip until
![Page 52: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/52.jpg)
Skip untillet (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)
![Page 53: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/53.jpg)
Collectlet (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)
![Page 54: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/54.jpg)
Manipulating multiple signals
![Page 55: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/55.jpg)
Combine latest
![Page 56: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/56.jpg)
Combine latest
![Page 57: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/57.jpg)
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 printedtextObserver.sendNext("John") // John - 1numberObserver.sendNext(2) // John - 2textObserver.sendNext("Mary") // Mary - 2
![Page 58: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/58.jpg)
Zip
![Page 59: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/59.jpg)
Ziplet (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 printedmenObserver.sendNext("Tom") // Nothing printedwomenObserver.sendNext("Lisa") // New couple - John and LisamenObserver.sendNext("Greg") // Nothing printedmenObserver.sendCompleted()womenObserver.sendNext("Sandra") // New couple - Tom and SandrawomenObserver.sendNext("Mary") // New couple - Greg and Mary, Completed
![Page 60: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/60.jpg)
Merge
![Page 61: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/61.jpg)
Mergelet (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") // JohnwomenObserver.sendNext("Lisa") // Lisa
![Page 62: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/62.jpg)
Handling errors
![Page 63: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/63.jpg)
Catching errorslet (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"
![Page 64: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/64.jpg)
Retryvar 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)") } }
![Page 65: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/65.jpg)
Promotinglet (numbersSignal, numbersObserver) = Signal<Int, NoError>.pipe()let (lettersSignal, lettersObserver) = Signal<String, NSError>.pipe()
numbersSignal .promoteErrors(NSError) .combineLatestWith(lettersSignal)
![Page 66: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/66.jpg)
Mapping errors
![Page 67: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/67.jpg)
Properties
![Page 68: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/68.jpg)
Properties• AnyProperty
• ConstantProperty
• MutableProperty
• DynamicProperty
![Page 69: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/69.jpg)
MutablePropertylet name = MutableProperty<String>("Bob")name.producer.startWithNext { (text) in print(text)}
name.modify { (name) -> String in return name + "!"}
name.value = "Lisa"
![Page 70: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/70.jpg)
DynamicPropertylet textProperty = DynamicProperty(object: textField, keyPath: "text")
textProperty.producer.startWithNext { (text) in print(text)}
textProperty.value = "Textfield text"
![Page 71: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/71.jpg)
Bindings
![Page 72: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/72.jpg)
Basic bindinglet property = MutableProperty<String>("")let (producer, _) = SignalProducer<String, NoError>.buffer(1)let (signal, _) = Signal<String, NoError>.pipe()
property <~ producerproperty <~ signal
![Page 73: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/73.jpg)
Action
![Page 74: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/74.jpg)
Create Actionlet action = Action<Int, String, NSError>({ (number) -> SignalProducer<String, NSError> in return SignalProducer<String, NSError> {observer, disposable in observer.sendNext("Number is \(number)") observer.sendCompleted() }})
![Page 75: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/75.jpg)
Create signal producerlet producer = action.apply(1)
![Page 76: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/76.jpg)
Execute actionprodcuer.startWithSignal { (signal, disposable ) in signal.observeNext({ (value) in print("\(value)") }) signal.observeFailed({ (actionError) in print("\(actionError)") })}
![Page 77: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/77.jpg)
Observing actionslet 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 }
![Page 78: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/78.jpg)
CocoaAction
![Page 79: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/79.jpg)
Prepare Actionvar 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() }})
![Page 80: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/80.jpg)
Create CocoaActionlet 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
![Page 81: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/81.jpg)
Schedulers• SchedulerType
• ImmediateScheduler• UIScheduler
• DateSchedulerType• QueueScheduler• TestScheduler
![Page 82: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/82.jpg)
Memory Management
![Page 83: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/83.jpg)
Disposables
![Page 84: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/84.jpg)
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 })}
![Page 85: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/85.jpg)
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() })}
![Page 86: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/86.jpg)
Cleaninglet 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 })}
![Page 87: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/87.jpg)
Disposing signallet 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() })}
![Page 88: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/88.jpg)
Closures
![Page 89: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/89.jpg)
What's the result?var value = 10let closure = { let date = NSDate().dateByAddingTimeInterval(2) QueueScheduler().scheduleAfter(date, action: { print(value) })}closure()value = 20
![Page 90: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/90.jpg)
Captured valuevar value = 10let closure = { [value] in let date = NSDate().dateByAddingTimeInterval(2) QueueScheduler().scheduleAfter(date, action: { print(value) })}closure()value = 20
![Page 91: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/91.jpg)
Weak, Strong, Unowned...
![Page 92: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/92.jpg)
Unownedlet closure = { [unowned self] in self.label.text = "test" }
![Page 93: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/93.jpg)
Weaklet closure = { [weak self] in guard let weakSelf = self else { return } self.label.text = "test" }
![Page 94: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/94.jpg)
Rex
![Page 95: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/95.jpg)
UIButtonlet cocoaAction = CocoaAction(action) { _ in }//without Rexbutton.addTarget(cocoaAction, action: CocoaAction.selector, forControlEvents: .TouchUpInside)//with Rex extensionsbutton.rex_pressed.value = cocoaAction
![Page 96: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/96.jpg)
UITextField, UILabel, MutableProperty
var titleValue = MutableProperty<String?>(nil)//without RextextField.rac_textSignal().subscribeNext { self.titleValue.value = $0 as? String}titleValue.producer.startWithNext { self.label.text = $0 self.label.hidden = $0?.characters.count < 5}//with RextitleValue <~ textField.rex_texttitleLabel.rex_text <~ titleValuetitleLabel.rex_hidden <~ titleValue.producer.map( { $0?.characters.count < 5 })
![Page 97: ReactiveCocoa workshop](https://reader034.vdocuments.net/reader034/viewer/2022042907/58729eda1a28ab07208b54cb/html5/thumbnails/97.jpg)
Let's see it in action