Code europe

71
Introduction to Functional Reactive Programming @EliSawic

Transcript of Code europe

Page 1: Code europe

Introduction to Functional Reactive

Programming

@EliSawic

Page 2: Code europe

About me

Eliasz SawickiBlog: www.eliaszsawicki.comTwitter: @EliSawic

@EliSawic

Page 3: Code europe

Agenda• What is functional reactive programming?

• Working with streams

• ReactiveSwift - Thinking in signals

• Example

@EliSawic

Page 4: Code europe

Functional Reactive Programming

@EliSawic

Page 5: Code europe

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).

@EliSawic

Page 6: Code europe

Reactive Programming

@EliSawic

Page 7: Code europe

Functional Programming

@EliSawic

Page 8: Code europe

Blocks

@EliSawic

Page 9: Code europe

Imperative vs

Declarative

@EliSawic

Page 10: Code europe

Imperative

@EliSawic

Page 11: Code europe

Imperativelet array = [0, 1, 2, 3, 4, 5]var evenNumbers = [Int]()for element in array { if element % 2 == 0 { evenNumbers.append(element) }}

@EliSawic

Page 12: Code europe

Declarative

@EliSawic

Page 13: Code europe

Declarativelet array = [0, 1, 2, 3, 4, 5]let evenNumbers = array.filter { $0 % 2 == 0 }

@EliSawic

Page 14: Code europe

Working with streams

@EliSawic

Page 15: Code europe

Stream

@EliSawic

Page 16: Code europe

Manipulating streams

@EliSawic

Page 17: Code europe

Map

@EliSawic

Page 18: Code europe

Filter

@EliSawic

Page 19: Code europe

Aggregating

@EliSawic

Page 20: Code europe

Manipulating multiple streams

@EliSawic

Page 21: Code europe

Combine latest

@EliSawic

Page 22: Code europe

Merge

@EliSawic

Page 23: Code europe

Chaining streams

@EliSawic

Page 24: Code europe

www.rxmarbles.com

@EliSawic

Page 25: Code europe

ReactiveSwift

@EliSawic

Page 26: Code europe

Thinking in Signals

@EliSawic

Page 27: Code europe

What is a signal?

@EliSawic

Page 28: Code europe

This screen is a signal

@EliSawic

Page 29: Code europe

Represents events over time

@EliSawic

Page 30: Code europe

Observing does not trigger side effects

@EliSawic

Page 31: Code europe

No random access to events

@EliSawic

Page 32: Code europe

Observe

@EliSawic

Page 33: Code europe

If you don't listen, it's gone

@EliSawic

Page 34: Code europe

What is event?

@EliSawic

Page 35: Code europe

Eventstruct Idea { var content: String var quality: Quality}

enum Quality { case Great case Average case Worst}

@EliSawic

Page 36: Code europe

Non-Terminating• Next

@EliSawic

Page 37: Code europe

Terminating

• Completed

• Failed

• Interrupted (Reactive Cocoa)

@EliSawic

Page 38: Code europe

Presentationlet (presentation, presentationObserver) = Signal<Idea, NoError>.pipe()

let content = "This presentation is a signal"let idea = Idea(content: content, quality: .Great)

presentationObserver.send(value: idea)presentationObserver.sendCompleted()

@EliSawic

Page 39: Code europe

Observingpresentation.observeValues { idea in remember(idea: idea)}presentation.observeCompleted { print("Time for a break")}

@EliSawic

Page 40: Code europe

Only great ideaslet greatIdeas = presentation.filter { idea in idea.quality == .Great}greatIdeas.observeValues { greatIdea in remember(idea: greatIdea)}

@EliSawic

Page 41: Code europe

Positive listenerlet greatPresentation = presentation.map { idea -> Idea in var greatIdea = idea greatIdea.quality = .Great return greatIdea}

@EliSawic

Page 42: Code europe

Signal producer

@EliSawic

Page 43: Code europe

Represents a tasks

@EliSawic

Page 44: Code europe

Possible side effects

@EliSawic

Page 45: Code europe

Does not start it's work if not asked

@EliSawic

Page 46: Code europe

Run presentationfunc runPresentation() -> SignalProducer<Idea, NoError> { return SignalProducer { observer, _ in observer.send(value: idea1) observer.send(value: idea2) ... observer.sendCompleted() }}

@EliSawic

Page 47: Code europe

Work with presentationrunPresentation().startWithValues { idea in print(idea)}

runPresentation().startWithSignal { (signal, _) in signal.observeValues({ idea in print(idea) })

signal.observeCompleted { print("Finally...") }}

@EliSawic

Page 48: Code europe

Cold vs Hot

@EliSawic

Page 49: Code europe

Properties

@EliSawic

Page 50: Code europe

Mutable Propertylet firstSlide = Slide(number: 1)let slide = MutableProperty<Slide>(firstSlide)slide.producer.startWithValues { (text) in print(text)}slide.value = Slide(number: 2)

@EliSawic

Page 51: Code europe

Bindings

@EliSawic

Page 52: Code europe

Binding examplelet slideNumber = MutableProperty<Int>(0)let (signal, _) = Signal<Slide, NoError>.pipe()

slideNumber <~ signal.map { return $0.number }

@EliSawic

Page 53: Code europe

Binding examplelet (signal, _) = Signal<Slide, NoError>.pipe()

label.reactive.text <~ signal.map { return "Slide: \($0.number)" }

@EliSawic

Page 54: Code europe

Schedulers

@EliSawic

Page 55: Code europe

Know where you aresignal.observe(on: QueueScheduler.main).observeValues { idea in print("Performing UI updates")}

@EliSawic

Page 56: Code europe

Memory Management

@EliSawic

Page 57: Code europe

Disposables

@EliSawic

Page 58: Code europe

Free your memorylet disposable = signal.observeValues { value in ...}

disposable.dispose()

@EliSawic

Page 59: Code europe

Release your producerslet disposable = producer.startWithValues { value in ...}

disposable.dispose()

@EliSawic

Page 60: Code europe

Example

@EliSawic

Page 61: Code europe

@EliSawic

Page 62: Code europe

How does it work?

@EliSawic

Page 63: Code europe

Is name valid?let isValidNameSignal = nameSignal.map { (name) -> Bool in return name.characters.count > 2}

@EliSawic

Page 64: Code europe

Is surname valid?let isValidSurnameSignal = surnameSignal.map { (surname) -> Bool in return surname.characters.count > 2}

@EliSawic

Page 65: Code europe

Is mail valid?let isValidMailSignal = mailSignal.map { (mail) -> Bool in let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}" let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx) return emailTest.evaluateWithObject(mail)}

@EliSawic

Page 66: Code europe

Combine Latestlet formDataSignal = combineLatest( isValidNameSignal, isValidSurnameSignal, isValidMailSignal)

@EliSawic

Page 67: Code europe

Is form valid?let isValidFormSignal = formDataSignal.map { (isValidName, isValidSurname, isValidMail) -> Bool in return isValidMail && isValidSurname && isValidMail}

@EliSawic

Page 68: Code europe

Update the stateisValidFormSignal.observeValues { isValid in updateButtonWith(state: isValid)}

@EliSawic

Page 69: Code europe

Bindinglet isValidForm = MutableProperty<Bool>(false)

isValidForm <~ isFormValidSignal

@EliSawic

Page 70: Code europe

Conclusion

@EliSawic

Page 71: Code europe

Thank you for your attention!sendCompleted()

@EliSawic