reactive cocoa

30
ReactiveCocoa @iacisclo

Upload: iacisclo

Post on 24-Jan-2015

367 views

Category:

Software


2 download

DESCRIPTION

slides about my talk reactiveCocoa

TRANSCRIPT

Page 1: Reactive cocoa

ReactiveCocoa

@iacisclo

Page 2: Reactive cocoa

Programación imperativa.

• Describe detalladamente los pasos a seguir.

• Continuos cambios de estado.

• El orden de ejecución es vital.

• Muchos condicionales.

Page 3: Reactive cocoa

Programación declarativa

• Tu describes directamente los resultados.

• El orden de ejecución no importa.

• Sin apenas condicionales.

• No hay que estar pendiente del estado.

Page 4: Reactive cocoa

ReactiveCocoa

• Compatible desde iOS 5.0+ y OS X 10.7+.

• Versión actual 2.2.4.

• Combina declarativa y funcional.

• Compatible con código no RAC.

Page 5: Reactive cocoa

¿Como? NSString *name = @"Belén"; NSString *surname = @“_Esteban”; NSString *completeName = [name stringByAppendingString:surname]; surname = @“_Esteban, háztelo mirar”; NSLog(@"%@",completeName);

El resultado sería “Belén_Esteban” pero con programación reactiva sería “Belén_Esteban, háztelo mirar”.

Page 6: Reactive cocoa

[self.textField.rac_textSignal subscribeNext:^(NSString *value) { self.lblValue.text = value; }];

Page 7: Reactive cocoa

// Imperative !for (NSString *device in devices) if ([device isEqualToString:@"iPod"]) { self.name = device; } } !// Reactive RAC(self, name) = [devices.rac_sequence.signal filter:^BOOL(NSString *device) { return [device isEqualToString:@"iPod"]; }];

Page 8: Reactive cocoa

Clases

• RACStream

• RACSignal

• RACSubscriber

• RACSubject

• RACCommand

• RACMulticastConnection

• RACSequence

• RACDisposable

• RACSheduler

Page 9: Reactive cocoa

RACStream

• El padre de Todos.

• Es un conjunto de valores.

• Las señales contienen RACStreams.

• Los valores se recuperan de forma secuencial.

Page 10: Reactive cocoa

RACCommand• Crea y se subscribe a una señal, generalmente

iniciada por UI.

self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id _) { self.lblValue.text = @"Button tapped"; return [RACSignal empty]; }];

RACCommand *createAccount = [[RACCommand alloc]initWithEnabled:formValid signalBlock:^RACSignal *(id input) { BOOL success = [IACClient logggin]; return [RACSignal return:@(success)]; }]; !self.createButton.rac_command = createAccount;

Page 11: Reactive cocoa

RACSignal• Envian 3 tipos de eventos: NEXT, ERROR, COMPLETED.

[signal subscribeNext:^(id x) { NSLog(@"en la subscripción"); } error:^(NSError *error) { NSLog(@"ha ocurrido un error."); } completed:^{ NSLog(@"señal completa"); }];

Page 12: Reactive cocoa

RACSignal RACSignal *executing = [racCommand.executing deliverOn:RACScheduler.mainThreadScheduler]; ! RACSignal *fieldTextColor = [executing map:^(NSNumber *x) { return x.boolValue ? [UIColor lightGrayColor] : [UIColor blackColor]; }];

RACSignal *signal = @[@"iPhone",@"iPad",@"iMac",@"iPod"].rac_sequence.signal; [[signal filter:^BOOL(NSString *value) { return [value isEqualToString:@"iPad"]; }]subscribeNext:^(NSString *filterValue) { self.lblValue.text = filterValue; }];

Page 13: Reactive cocoa

RACSignal

!RACSignal *formValid = [RACSignal combineLatest:@[ self.firstNameField.rac_textSignal, self.lastNameField.rac_textSignal, self.emailField.rac_textSignal, ] reduce:^(NSString *firstName, NSString *lastName, NSString *email){ return @(firstName.length > 0 && lastName.length > 0 && email.length > 0); }];

Page 14: Reactive cocoa

RACSubject• Señal que se puede controlar.

RACSubject *letters = [RACSubject subject]; [letters subscribeNext:^(NSString *letter) { NSLog(@"%@",letter); } completed:^{ NSLog(@"complete"); }]; [letters sendNext:@"A"]; [letters sendNext:@"B"]; [letters sendCompleted];

Page 15: Reactive cocoa

rac_liftSelector:withSignals:

! self.delegate = [RACSubject subject]; ![self.navigationController rac_liftSelector:@selector(pushViewController:animated:) withSignals:self.delegate,[RACSignal return:@YES], nil]; !///// !IACDetailViewController *detailVC = [self.storyboard instantiateViewControllerWithIdentifier:@"IACDetailViewController"]; ! [self.delegate sendNext:detailVC]; !

Page 16: Reactive cocoa

RACSubscriber• Todo objeto que espera o es capaz de

subscribirse a una señal

[[self saveImage:[UIImage imageNamed:@"image1"] withName:@"image1"]then:^RACSignal *{ NSLog(@"image guardada correctamente"); return nil; }]; !///////// !-(RACSignal *)saveImage:(UIImage *)image withName:(NSString *)name{ return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:@"savedImage.png"]; NSData *imageData = UIImagePNGRepresentation(image); BOOL error = [imageData writeToFile:savedImagePath atomically:NO]; if (error) { [subscriber sendError:nil]; }else{ [subscriber sendCompleted]; } return nil; }]; }

Page 17: Reactive cocoa

RACSequence• Colecciones, señales guiadas.

RACSequence *devices = @[@"iPhone",@"iPad",@"iPod"].rac_sequence; RACSequence *computers = @[@"iMac",@"Mac Mini",@"Macbook Air",@"Macbook Pro"].rac_sequence; RACSequence *concatenated = [devices concat:computers]; [concatenated.signal subscribeNext:^(id x) { NSLog(@"%@",x); }];

Page 18: Reactive cocoa

RACSequence• Colecciones, señales guiadas.

RACSignal *devices = @[@"iPhone",@"iPad",@"iPod"].rac_sequence.signal; RACSignal *sequenced = [[devices doNext:^(NSString *device) { NSLog(@"trabajamos con el objeto %@", device); }] then:^{ return @[@"iMac",@"Mac Mini",@"Macbook Air",@"Macbook Pro"].rac_sequence.signal; }]; [sequenced subscribeNext:^(NSString *computer) { NSLog(@"%@",computer); }];

Page 19: Reactive cocoa

do… RACSignal *sequenced = [[[[devices doNext:^(NSString *device) { ! NSLog(@“antes de la subscripción %@“,device); ! }]doError:^(NSError *error) { ! NSLog(@"antes del error: %@", error); ! }]doCompleted:^{ ! NSLog(@"señal antes de ser completada”); ! }]then:^{ ! NSLog(@"señal ya completada”); ! }];

Page 20: Reactive cocoa

RACDisposable• Baja o limpieza de señales.

RACDisposable *subscription = [self.textField.rac_textSignal subscribeNext:^(NSString *text) { self.lblValue.text = text; }]; // en un futuro; [subscription dispose];

Page 21: Reactive cocoa

Delegados• Podemos sustituir delegados facilmente

self.textView.delegate = self; [[self rac_signalForSelector:@selector(textViewDidChange:)fromProtocol: @protocol(UITextViewDelegate)]subscribeNext:^(RACTuple *arguments) { UITextView *textview = arguments.first; }];

UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Alert" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil]; [alert show]; [alert.rac_buttonClickedSignal subscribeNext:^(NSNumber *index) { NSLog(@"%@",index); }];

Page 22: Reactive cocoa

Eventos de control• UIControlEvetTouchDown

• UIControlEventTouchDownRepeat

• UIControlEventTouchDragInside

• UIControlEventTouchDragOutside

• UIControlEventTouchDragEnter

• UIControlEventTouchDragExit

• UIControlEventTouchUpInside

• UIControlEventTouchUpOutside

• UIControlEventTouchCancel

• UIControlEventValueChanged

• UIControlEventEditingDidBegin

• UIControlEventEditingChanged

• UIControlEventEditingDidEnd

• UIControlEventEditingDidEndOnExit

• UIControlEventAllTouchEvents

• UIControlEventAllEditingEvents

• UIControlEventApplicationReserved

• UIControlEventSystemReserved

Page 23: Reactive cocoa

Eventos de control

[[stepper rac_signalForControlEvents:UIControlEventAllTouchEvents] subscribeNext:^(UIStepper *stepper) { self.lblValue.text = [NSString stringWithFormat:@"%f",stepper.value]; }];

RAC(self.textField, textColor) = [[self.textField rac_signalForControlEvents: UIControlEventAllEvents]map:^id(UITextField *textfield) { if (textfield.text.length >3) { return [UIColor blackColor]; }else{ return [UIColor redColor]; } }];

Page 24: Reactive cocoa

RACSheduler• GCD en RAC.

[[self.textField.rac_textSignal deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSString *value) { self.lblValue.text = value; }];

RACScheduler *scheduler = [RACScheduler schedulerWithPriority:RACSchedulerPriorityBackground]; [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { return nil; }]subscribeOn:scheduler];

Page 25: Reactive cocoa

RACSheduler////// ![[[self signalForLoadingImage:tweet.profileImageUrl] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(UIImage *image) { cell.twitterAvatarView.image = image; }]; !/////// !-(RACSignal *)signalForLoadingImage:(NSString *)imageUrl { RACScheduler *scheduler = [RACScheduler schedulerWithPriority:RACSchedulerPriorityBackground]; return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]; UIImage *image = [UIImage imageWithData:data]; [subscriber sendNext:image]; [subscriber sendCompleted]; return nil; }]subscribeOn:scheduler]; }

Page 26: Reactive cocoa

Memoria

__weak ViewController *bself = self; [[self.searchText.rac_textSignal map:^id(NSString *text) { return [self isValidSearchText:text] ? [UIColor whiteColor] : [UIColor yellowColor]; }] subscribeNext:^(UIColor *color) { bself.searchText.backgroundColor = color; }];

Page 27: Reactive cocoa

Memoria

#import "RACEXTScope.h" !! @weakify(self) [[self.searchText.rac_textSignal map:^id(NSString *text) { return [self isValidSearchText:text] ? [UIColor whiteColor] : [UIColor yellowColor]; }] subscribeNext:^(UIColor *color) { @strongify(self) self.searchText.backgroundColor = color; }];

Page 28: Reactive cocoa

RACObserve(TARGET, KEYPATH)

@weakify(self) [RACObserve(self, modelArray) subscribeNext:^(id x) { @strongify(self) [self.collectionView reloadData]; }];

[[[RACObserve(photoModel, imageData)filter:^BOOL(id value) { return value != nil; }]map:^id(id value) { return [UIImage imageWithData:value]; }]setKeyPath:@keypath(self.imageView, image) onObject:self.imageView];

Page 29: Reactive cocoa

RAC(TARGET, …)

RAC(self,dateAdded) = [RACObserve(self.model,dateAdded)map:^(NSDate*date){ return [[ViewModel dateFormatter] stringFromDate:date]; }];

!RAC(self, name) = self.textField.rac_textSignal;

Page 30: Reactive cocoa

return;