Slide 1

Slide 1 text

Func%onal)Reac%ve)Programming Oscar&Swanros MobileCoder.mx mobilecoder.mx,-2015 1

Slide 2

Slide 2 text

@Swanros h"p:/ /swanros.com mobilecoder.mx,-2015 2

Slide 3

Slide 3 text

I"got"bored. mobilecoder.mx,-2015 3

Slide 4

Slide 4 text

Un#l... mobilecoder.mx,-2015 4

Slide 5

Slide 5 text

WWDC$'14 mobilecoder.mx,-2015 5

Slide 6

Slide 6 text

I'm$running$away$from$OOP$and$the$ MVC$pa9ern. mobilecoder.mx,-2015 6

Slide 7

Slide 7 text

And$also$a$li*le$bit$ of... mobilecoder.mx,-2015 7

Slide 8

Slide 8 text

typedef (^myBlock)(BOOL isThisCool) = ^void() { // }; mobilecoder.mx,-2015 8

Slide 9

Slide 9 text

Callback'hell,'anyone? mobilecoder.mx,-2015 9

Slide 10

Slide 10 text

Because'it'gets'boring'quickly... ! mobilecoder.mx,-2015 10

Slide 11

Slide 11 text

Enter&FRP. mobilecoder.mx,-2015 11

Slide 12

Slide 12 text

Func%onal)Reac%ve)Programming = Func%onal)Programming)+)Reac%ve)Programming mobilecoder.mx,-2015 12

Slide 13

Slide 13 text

Func%onal)Programming In#a#purely'func+onal#language,#f(x)#will#return#the#same#value#for# the#same#x. Always. mobilecoder.mx,-2015 13

Slide 14

Slide 14 text

Reac%ve'Programming In#a#reac%ve#language,#y=f(x) y!will!always!stay!up!to!date!when!x! changes. mobilecoder.mx,-2015 14

Slide 15

Slide 15 text

mobilecoder.mx,-2015 15

Slide 16

Slide 16 text

FRP!is!about!datatypes!that! represent!a!value!over!&me. mobilecoder.mx,-2015 16

Slide 17

Slide 17 text

At#the#core#of#FRP#are#Signals. mobilecoder.mx,-2015 17

Slide 18

Slide 18 text

A"Signal"is"a"value"that"changes"over()me. mobilecoder.mx,-2015 18

Slide 19

Slide 19 text

done := make(chan bool) watcher := notificator.New() for { select { case newText := <-watcher.Next: fmt.Println(newText) case error := <-watcher.Error: log.Fatal(error) } } <-done mobilecoder.mx,-2015 19

Slide 20

Slide 20 text

[self.emailTextField.rac_textSignal subscribeNext:^(id value) { NSLog(@"%@", value); }]; mobilecoder.mx,-2015 20

Slide 21

Slide 21 text

mobilecoder.mx,-2015 21

Slide 22

Slide 22 text

@interface ViewController() // ... self.emailTextField.delegate = self; // ... -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { NSLog(@"%@", [textField.text stringByAppendingString:string]); return YES; } mobilecoder.mx,-2015 22

Slide 23

Slide 23 text

[self.emailTextField.rac_textSignal subscribeNext:^(id value) { NSLog(@"%@", value); }]; mobilecoder.mx,-2015 23

Slide 24

Slide 24 text

// 1 RACSignal *usernameTextSignal = self.usernameTextField.rac_textSignal; RACSignal *passwordTextSignal = self.passwordTextField.rac_textSignal; // 2 RACSignal *validUsernameSignal = [[usernameTextSignal map:^id(NSString *username) { return @([self isValidUsername:username]); }] distinctUntilChanged]; RACSignal *validPasswordSignal = [[passwordTextSignal map:^id(NSString *password) { return @([self isValidPassword:password]); }] distinctUntilChanged]; // 3 RAC(self.usernameTextField, backgroundColor) = [validUsernameSignal map:^id(NSNumber *usernameValid) { return [usernameValid boolValue] ? [UIColor greenColor] : [UIColor redColor]; }]; RAC(self.passwordTextField, backgroundColor) = [validPasswordSignal map:^id(NSNumber *passwordValid) { return [passwordValid boolValue] ? [UIColor greenColor] : [UIColor redColor]; }]; // 4 [[RACSignal combineLatest:@[validUsernameSignal, validPasswordSignal] reduce:^id(NSNumber *usernameValid, NSNumber *passwordValid){ return @([usernameValid boolValue] == YES && [passwordValid boolValue] == YES); }] subscribeNext:^(NSNumber *loginButtonActive) { self.loginButton.enabled = [loginButtonActive boolValue]; }]; mobilecoder.mx,-2015 24

Slide 25

Slide 25 text

mobilecoder.mx,-2015 25

Slide 26

Slide 26 text

Func%onal)Reac%ve)Programming)lets)you)be)more)concise)with)your)code. mobilecoder.mx,-2015 26

Slide 27

Slide 27 text

Focus&on&what&you&want&to&do, and$not$on$how$to$do$it. mobilecoder.mx,-2015 27

Slide 28

Slide 28 text

(That's(the(Func.onal(mo#o.) mobilecoder.mx,-2015 28

Slide 29

Slide 29 text

Resources? mobilecoder.mx,-2015 29

Slide 30

Slide 30 text

Ruby:&frapuccino class Button def push emit(:pushed) end end button = Button.new stream = Frappuccino::Stream.new(button) counter = stream .map {|event| event == :pushed ? 1 : 0 } .inject(0) {|sum, n| sum + n } counter.now # => 0 button.push counter.now # => 1 mobilecoder.mx,-2015 30

Slide 31

Slide 31 text

JS:$RxJS var source = getStockData(); source .filter(function (quote) { return quote.price > 30; }) .map(function (quote) { return quote.price; }) .forEach(function (price) { console.log('Prices higher than $30: $' + price); }); mobilecoder.mx,-2015 31

Slide 32

Slide 32 text

Learning(FRP(is(hard. mobilecoder.mx,-2015 32

Slide 33

Slide 33 text

But$it's$worth$it. mobilecoder.mx,-2015 33

Slide 34

Slide 34 text

Ques%ons? mobilecoder.mx,-2015 34