ReactiveCocoa - Functional Reactive Programming concepts in iOS

34
ReactiveCocoa functional reactive programming in iOS Andrei Popa

Transcript of ReactiveCocoa - Functional Reactive Programming concepts in iOS

ReactiveCocoa functional reactive programming in iOS

Andrei Popa

A. current challenges in programming

- keeping state, inputs, asynchronous tasks, callback hell

B. how does Functional Reactive Programming solve them

- the functional aspect

- the reactive aspect

C. ReactiveCocoa - mature FRP implementation for iOS

D. Examples

- the input is all the sources of action for your app: button taps, keyboard events, timer triggers, GPS events, web service responses, etc.

- the output at any one time is the result of combining all inputs.

- ft (input) = output

- but unlike the classic input / output design, this input and output happens more than once. It’s not just a single input - work - output, the cycle continues while the app is open

first problem: state

first problem: state

And so our only tool for dealing with all these different things is state.

• obviously this is highly error prone

• to make matters worse, this type of code will often produce bugs that are incredibly hard, if not impossible to identify in any

automated way

• state introduces complexity. And worse, it introduces complexity that grows more than linearly with the size of our app

first problem: state

nondeterministic vs deterministic

nondeterministic vs deterministic

- most developers have experienced the problems of non-determinism when a client calls in with a problem, but the problem is not reproducible even by retracing the exact same steps

- if the program was deterministic, then retracing those exact

steps would always produce the error, no exception

- for testing and quality assurance purposes, reproducibility is essential

types of inputs - iOS

asynchronous operations

- network requests - resource loading - image processing - bluetooth operations - file I/O

What happens when several different asynchronous operations must

be executed in some set order (serialized)?

asynchronous operations callback hell aka Pyramid of Doom

asynchronous operations callback hell aka Pyramid of Doom

functional programming = stateless programming

- fundamental operation is the application of functions to

arguments.

- passing functions and blocks as objects

- there is no mutable state in functional programming

- f (input) = output , always produces the same output

given the same input. Always.

- it doesn’t rely / change on data outside the current function

functional programming = stateless programming

If we had machines that had infinite computational power, what problems would we be able to solve?

- Alonzo Church developed λ - lambda calculus

Computability described via λ-calculus gave rise to Functional Programming

- Alan Turing developed Turing machine

Computability via Turing machines gave rise to Imperative Programming.

Church-Turing thesis: The notion of intuitive computability is exactly captured by λ-definability or by Turing computability.

who is using functional programming ?

Some of the most complex systems written using Erlang: - telecommunication and traffic control systems - Ericsson (highly tolerant and scalable telecommunication switches)

- Facebook (Facebook chat backend)

- T-Mobile (advanced call control services)

- WhatsApp server - average of 8 billion inbound messages and 12 billion outbound

messages a day - WhatsApp scales up to more than a million connections on a single

box thanks to Erlang’s amazing scalability

reactive programming

In computing, reactive programming is a programming paradigm oriented around data flows and the propagation of change.

We don’t care how it happens – just that we can rely on its truthfulness.

functional reactive programming time-varying values

- lets us define our app in terms of the time-varying values and ensures changes propagate as needed.

- the result of asynchronous work is really just a time-varying

value that only has a value once the work is done

- a UI element’s value could be seen as a time-varying value

that changes as the user interacts with it

- if my app is running on a mobile device, the device’s GPS

coordinates is a time-varying value

1. model any reaction to any event using signals - wrap calls in RACSignal (ObjC) / SignalProducer (Swift)

2. manipulate, transform, combine values sent by signals - map, filter, flattenMap, zip, concat, merge, … - throttle, delay, repeat, then, take, distinctUntilChanged, … - deliverOn(someThread), subscribeOn(someOtherThread) - subscribe

ReactiveCocoa provides a common interface for all events : signal

ReactiveCocoa unifies all of Cocoa’s common patterns for asynchrony and event handling

ReactiveCocoa unifies all of Cocoa’s common patterns for asynchrony and event handling

Examples

1) Take pictures burst mode

2) Apply filter

3) Put frame

4) Send to back for generating animated GIF

- (RACSignal *) generateCats { return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // my long async call ——————————————————————————- [[MyCameraManager sharedInstance] takePicturesBurstMode:^(UIImage *image, NSError *error) { if (error) { [subscriber sendError:error]; }

else { [subscriber sendNext:image]; [subscriber sendCompleted]; } }]; // ——————————————————————————————————————————————

return nil; }]; }

1) take pictures

- (UIImage *) applyFilter(UIImage *) {

return ;

}

[[signalFactory generateCats]

map:^id(UIImage *cat) { return applyFilter(cat); }];

2) apply filter

- (UIImage *) putFrame(UIImage *)image {

return image ;

}

[[[signalFactory generateCats]

map:^id(UIImage *cat) { return applyFilter(cat); }]

map:^id(UIImage *cat) { return putFrame(cat); }];

3) put frame

[[[[[signalFactory generateCats]

map:^id(UIImage *cat) { return applyFilter(cat); }]

map:^id(UIImage *cat) { return putFrame(cat); }]

collect] // combine all next events into one NSArray

flattenMap:^RACStream *(NSArray *allCats) {

// [signalFactory sendAsyncToBackend:allCats] is a RACSignal return [signalFactory sendAsyncToBackend:allCats];

}]; // this will still be a RACSignal

4) Send to back for generating animated GIF

[[[[[[signalFactory generateCats] // take pictures

map:^id(UIImage *cat) { return applyFilter(cat); }] // apply filter

map:^id(UIImage *cat) { return putFrame(cat); }]] // put frame

collect] // get all the processed images

flattenMap:^RACStream *(NSArray *allCats) { return [signalFactory sendAsyncToBackend:allCats]; }] // send async call and wait for the result

// signal is started when someone subscribes subscribeNext:^(UIImage *animatedGIF) { // success!, display GIF } error:^(NSError *error) { // error }];

5) see the result

ReactiveCocoa Bindings in MVVM architecture using RAC Signals

- http://rxmarbles.com/

- http://www.sprynthesis.com/2014/06/15/why-reactivecocoa/

- http://www.sprynthesis.com/2014/12/06/reactivecocoa-mvvm-introduction/

- http://www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1

- https://developers.soundcloud.com/blog/building-the-new-ios-app-a-new-paradigm

- https://github.com/popaaaandrei/StarterProject_RACSwift2

The end. Thank you! Q&A