Slide 1

Slide 1 text

REACTIVECOCOAೖ໳ Signals, SignalProducers and Events! Oh my!

Slide 2

Slide 2 text

ࣗݾ঺հ Nicholas Maccharoli (χίϥεɾϚΧϩʔϦ) VASILYͰiOSΤϯδχΞΛ͍ͯ͠·͢ OSSͱ͔Swift Evolutionʹߩݙ͍ͯ͠·͢ ࠷ۙSwift Evolution SE-0053ΛఏҊͯ͠Swift3.0ʹ ࠾༻͞Ε·ͨ͠ʂ github.com/nirma @din0sr

Slide 3

Slide 3 text

FRP(FUNCTIONAL REACTIVE PROGRAMMING) ͷϝϦοτ͸ʁ > ίʔυϊΠζ͕ݮΒͤ·͢ > @IBAction, NSNotificationCenter͓ΑͼCallback/ DelegateͷύλʔϯΑΓ΋ɺ΋ͬͱγϯϓϧ ͳ࣮૷͕Ͱ͖·͢ɻ

Slide 4

Slide 4 text

ྫ: ϦϑϨογϡϘλϯͷΫϦοΫΠϕϯτ (Ұൠతͳ࣮૷) @IBAction func refreshButtonClicked(sender: AnyObject) { updateViewForState(.Loading) performNetworkRequest() { updateModel() dispatch_async(dispatch_get_main_queue()) { updateViewForState(.Success) } } }

Slide 5

Slide 5 text

refreshButtonClicked:͕ݺ͹ΕͨΒ 1. ϘλϯͷදࣔΛߋ৽ 2. ϩʔσΟϯάΞΠίϯΛදࣔ 3. ωοτϫʔΫϦΫΤετ 4. ϦΫΤετ͕׬ྃͨ͠ΒCallbackͰUIͱϞσ ϧΛߋ৽͢Δ

Slide 6

Slide 6 text

Ұͭͷϝιουͷதʹෳ਺ͷ੹೚ͷॲཧ͕ ݻ·͍ͬͯͯྑ͘ͳ͍ɻ γϯϓϧʹॻ͖׵͍͑ͨɻ

Slide 7

Slide 7 text

ϧʔϓॲཧͩͱ͜ΜͳΠϝʔδ Before: var counter = 0 var animationImages = [UIImage]() while counter < 10 { let imageString = "animation_image_\(counter)" if let image = UIImage(named: imageString) { animationImages += [image] } }

Slide 8

Slide 8 text

ϧʔϓॲཧͩͱ͜ΜͳΠϝʔδ After: (0..<10).flatMap { UIImage(named: "animation_image_\($0)") }

Slide 9

Slide 9 text

RAC FTW!

Slide 10

Slide 10 text

REACTIVECOCOAͱRXͷҧ͍ > Naming Convention > Rx: Hot Observable, Cold Observable > ReactiveCocoa: Signal, SignalProducer > Cocoaઐ༻API֦ு > ΑΓγϯϓϧͳઃܭ > etc

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

YES, SIGNALS! SignalͰΠϕϯτΛड͚औͬͯObserverͱ͔ DisposableͰSignalૢ࡞͕Ͱ͖·͢ɻ

Slide 13

Slide 13 text

EVENTS... /// Signals must conform to the grammar: /// `Next* (Failed | Completed | Interrupted)?` public enum Event { /// A value provided by the signal. case Next(Value) /// The signal terminated because of an error. No further events will be /// received. case Failed(Error) /// The signal successfully terminated. No further events will be received. case Completed /// Event production on the signal has been interrupted. No further events /// will be received. case Interrupted /// Whether this event indicates signal termination (i.e., that no further /// events will be received). }

Slide 14

Slide 14 text

SIGNALS, CHEAP ৗʹൃੜ͠͏ΔΠϕϯτετϦʔϜ > UIίϯτϩʔϧ > APIϦΫΤετ > DB Read / Write > UINotificationCenter > ͳΜͰ΋

Slide 15

Slide 15 text

SIGNAL࡞੒ͱ࢖͍ํ let (userNameTextSignal, observer) = Signal.pipe() userNameTextSignal.observeNext { userName in print("Next Event: \(userName)") } observer.sendNext("l") // Next Event: l observer.sendNext("la") // NExt Event: la observer.sendNext("lat") // Next Event: lat observer.sendNext("latt") // Next Event: latn observer.sendNext("lattn") // Next Event: lattn observer.sendNext("lattne") // Next Event: lattne observer.sendNext("lattner") // Next Event: lattner observer.sendCompleted()

Slide 16

Slide 16 text

SIGNAL'S FRIENDS MAP, FILTER, REDUCE RAC Marbles

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

SIGNAL OPERATORS IN ACTION - FILTER let (userNameTextSignal, observer) = Signal.pipe() let improvedUserNameTextSignal = userNameTextSignal.filter { $0.characters.count > 4 } improvedUserNameTextSignal.observeNext { userName in print("Next Event: \(userName)") } observer.sendNext("lattn") observer.sendNext("lattne") observer.sendNext("lattner") observer.sendCompleted()

Slide 25

Slide 25 text

طଘͷSIGNAL͔Β৽͍͠SIGNALΛ࡞Δ let (userNameTextSignal, observer) = Signal.pipe() let userNameValidSignal = userNameTextSignal.map { return $0.characters.count > 5 } let backgroundColorSignal = userNameValidSignal.map { return $0 ? UIColor.greenColor() : UIColor.redColor() }

Slide 26

Slide 26 text

SIGNALS & END OF LIFE swiftͷGeneratorTypeͱಉ͡Α͏ʹҰճSignal Λ࢖͍ऴΘͬͨΒ࠶ར༻Ͱ͖ͳ͍ɻ

Slide 27

Slide 27 text

SIGNALPRODUCER (COLD SIGNALS) > SignalProducers ͸ Signal ͷϑΝΫτϦʔ > ߪಡ͠ͳ͍͔͗Γɺॲཧ͸։࢝͞Εͳ͍ > Signal Operators can be 'Lifted'

Slide 28

Slide 28 text

SIGNALPRODUCER - NOTHING var userNameProducer = SignalProducer { (observer, disposable) in ["foo", "bar", "zap", "bin", "fizz"].forEach { userName in print("Sending Username: \(userName)") observer.sendNext(userName) } }

Slide 29

Slide 29 text

SIGNALPRODUCER - SOMETHING var userNameProducer = SignalProducer { (observer, disposable) in ["foo", "bar", "zap", "bin", "fizz"].forEach { userName in print("Sending Username: \(userName)") observer.sendNext(userName) } } userNameProducer.startWithNext { userName in print("Received Username: \(userName)") }

Slide 30

Slide 30 text

OUTPUT Sending Username: foo Received Username: foo Sending Username: bar Received Username: bar Sending Username: zap Received Username: zap Sending Username: bin Received Username: bin Sending Username: fizz Received Username: fizz

Slide 31

Slide 31 text

SIGNALPRODUCER - SIGNALPRODUCER͔ΒSIGNALPRODUCER࡞ Δ var userNameProducer = SignalProducer { (observer, disposable) in ["foo", "bar", "zap", "bin", "fizz"].forEach { userName in print("Sending Username: \(userName)") observer.sendNext(userName) } } userNameProducer.startWithNext { userName in print("Received Username: \(userName)") } let zCounterSignal = userNameProducer.map { $0.containsString("z") } zCounterSignal.startWithNext { if $0 { print("Contains z!") } else { print("No z here.") } }

Slide 32

Slide 32 text

OUTPUT No z here. No z here. Contains z! No z here. Contains z!

Slide 33

Slide 33 text

RAC4.0ͷAPIมߋ > Based on Swift 2.0 > RACSignal͕ͳ͘ͳΓ·ͨ͠ (This is a lie.) > RAC3.0͔ΒRACSignal (HOT, COLD) ͕ Signal, SignalProducerʹมߋ > Global Functions Protocol Extensions > |>(Pipe-Left)͸ී௨ͷ.(Dot Operator)ʹมߋ

Slide 34

Slide 34 text

·ͱΊ > RAC4͸͍͍FRPϥΠϒϥϦͱͯ͠ઃܭ͕ྑ͍ > ίϛϡχςΟ͕ϔϧγʔͰਐԽ΋ૣ͍͚ Ͳɺ·ͩϨΨγʔίʔυ͕࢒͍ͬͯΔͷ Ͱ'5/5'Λ্͛ΒΕͳ͍Ͱ͢ > Cocoa֦ு͸ศར͚ͩͲɺϥΠϒϥϦΛං େԽ͍ͤͯ͞Δ