iOS Delegates - Mobile Conf Rio 2014

Post on 05-Jun-2015

389 views 4 download

description

Presented at Mobile Conf Rio 2014, Brazil. The content is in Brazilian Portuguese. Discussion of the Delegate pattern and its implementation in iOS API. Samples from the SDK and a custom interaction using delegates. Shows techniques such as performSelector: calls, delegation through protocol and delegation using blocks. Code samples: https://github.com/osnipso/mobileconf2014 Caelum IP-67 course on iOS (in Brazilian Portuguese): http://www.caelum.com.br/curso-ios-iphone-ipad/

Transcript of iOS Delegates - Mobile Conf Rio 2014

DELEGATESDesvendando esse poderoso padrão

na API do iOS

APRESENTAÇÃO

Osni Oliveira

osni.oliveira@caelum.com.br

@osnipso

github.com/osnipso

CONHECIMENTO

• Básico de Objective-C

• Conceitos fundamentais do iOS

• Views

• Actions

•Outlets

slideshare.net/osnipso/primeiros-passos-no-ios-com-objectivec

DELEGATES

• Padrão de Projeto (Design Pattern)

•Divisão de responsabilidades

• Princípio da responsabilidade única

• Comunicação entre objetos

• Inversão de Controle (IoC)

DELEGATES

Colaboração entre objetos

IMPORTÂNCIA

• É *o* padrão mais importante no iOS

•Muito utilizado pela API

•Muito utilizado pelos desenvolvedores

• Imprescindível compreender

•Necessário dominar

• Boa prática utilizar - padronização

DEFINIÇÕES

•Delegation (iOS Developer Library - Cocoa Core Competencies)

https://developer.apple.com/library/ios/documentation/general/conceptual/DevPedia-CocoaCore/Delegation.html

•Delegates and Data Sources (iOS Developer Library - Concepts in Objective-C Programming)

https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources.html#//apple_ref/doc/uid/TP40010810-CH11

CONCEITO

Apple (Cocoa Core Competencies):

Delegação é um padrão simples e poderoso em que um objeto em um programa age no lugar de, ou em coordenação com outro objeto.

(...)

O objeto que delega é tipicamente um objeto do framework e o delegado é tipicamente um objeto controller customizado.

CONCEITO

Delega(framework) Delegado

MensagemProtocolo (opcional)

CONCEITO

• Recebe o delegado como dependência (injeção)

• Faz a “primeira parte” da tarefa

• Envia a mensagem

Delega(framework)

CONCEITO

• É injetado para o objeto que delega

• Garante a implementação da mensagem

• Faz a “segunda parte” da tarefa

Delegado

CONCEITO

•Opcional

• Contrato formal

• Acoplamento através do contrato (leve)

Protocolo

CONCEITO

Dois objetos colaboram para realizar uma tarefa.

O primeiro, faz até onde ele consegue fazer.

O que ele não consegue? Delega para o segundo!

CONCEITO

Delega(framework) Delegado

MensagemProtocolo (opcional)

EXEMPLO: UIAlertView

(ViewController.h)

@interface ViewController : UIViewController <UIAlertViewDelegate>

(ViewController.m)

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Exemplo 1" message:@"Começando com delegates" delegate:self cancelButtonTitle:@"Cancela" otherButtonTitles:@"Ok", nil];

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { ... }

EXEMPLO: UIAlertView

UIAlertView ViewController

alertView:clickedButtonAtIndex:

UIAlertViewDelegate

delegatereferência

EXEMPLO: UIAlertView

• Sabe exibir a mensagem e os botões

• Sabe qual botão foi tocado (“clicado”) pelo usuário

•Não sabe o que fazer a partir desse ponto!

•Depende da aplicação

• Aciona o delegado para fazer

EXEMPLO: UIImagePickerController

(ViewController.h)

@interface ViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate>

(ViewController.m)

UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;imagePicker.delegate = self; [self presentViewController:imagePicker animated:YES completion:nil];

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { ... }

EXEMPLO: UIImagePickerController

UIImagePickerController ViewController

imagePickerController:didFinishPickingMediaWithInfo:

UINavigationControllerDelegate (*)UIImagePickerControllerDelegate

delegatereferência

EXEMPLO: UIImagePickerController

• Sabe exibir a galeria de imagens/vídeos (câmera, etc.)

• Sabe qual image/vídeo foi selecionado pelo usuário

•Não sabe o que fazer a partir desse ponto!

•Depende da aplicação

• Aciona o delegado para fazer

OUTROS EXEMPLOS

• UITableView

• UITableViewDelegate (interação com UI / exibição avançada)

• UITableViewDataSource (exibição básica)

OUTROS EXEMPLOS

• UIApplicationDelegate

(AppDelegate.h)

@interface AppDelegate : UIResponder <UIApplicationDelegate>

E O CONTRATO?

• Acoplamento a um protocolo específico

•Melhor que acoplar diretamente à classe...

•Obrigatoriedade de implementar todas as mensagens (?)

• Péssimo. Implementações vazias, adapters, etc.

EXEMPLO - SEM PROTOCOLO

• UIPickerController, porém seleciona ao confirmar

• Permite cancelar seleção

• Exibido como modal

EXEMPLO - SEM PROTOCOLO

• MYPickerViewController é quem implementa UIPickerViewDataSource, UIPickerViewDelegate

(MYPickerViewController.h)

@interface MYPickerViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>

• Exibe conteúdo fixo

• Seguindo a mesma idéia, podemos perguntar a um DataSource o que exibir... (desafio)

EXEMPLO - SEM PROTOCOLO

• Precisamos usar performSelector:

•Delegate pode ser genérico, mas precisa implementar o protocolo NSObject

(MYPickerViewController.h)

@property (weak, atomic) id<NSObject> delegate;

(MYPickerViewController.m)

if ([self.delegate respondsToSelector:@selector(pickedItem:)]) { [self.delegate performSelector:@selector(pickedItem:) withObject:@(self.selectedItem)];}

EXEMPLO - SEM PROTOCOLO

• Problemas com o compilador:

• Até dá pra desligar esse aviso, mas...

EXEMPLO - SEM PROTOCOLO

MYPickerViewController ViewController

cancelPicking (opcional)pickedItem: (opcional)

NSObject

delegatereferência

EXEMPLO - SEM PROTOCOLO

Prós:

•Menos trabalho

• Sem implementações desnecessárias, adapters

Contras:

• Contrato implícito!

• Sem autocomplete

• Sem ajuda do compilador

•Muito limitado!

EXEMPLO - SEM PROTOCOLO

Limitações

• Protocolo NSObject

performSelector:

performSelector:withObject:

performSelector:withObject:withObject:

• Boxing (syntax sugar)

EXEMPLO - COM PROTOCOLO

(MYPickerViewController.h)

@class MYPickerViewController;

@protocol MYPickerViewControllerDelegate <NSObject>

@optional- (void)cancelPickerViewController: (MYPickerViewController *)pickerViewController;

@required- (void)pickerViewController:(MYPickerViewController *)pickerViewController pickedItem:(NSInteger)itemIndex;

@end

@property (weak, atomic) id<MYPickerViewControllerDelegate> delegate;

EXEMPLO - COM PROTOCOLO

(MYPickerViewController.m)

- (IBAction)cancelPicking:(id)sender{ if ([self.delegate respondsToSelector: @selector(cancelPickerViewController:)]) { [self.delegate cancelPickerViewController:self]; }}

- (IBAction)confirmPicking:(id)sender{ [self.delegate pickerViewController:self pickedItem:self.selectedItem];}

EXEMPLO - COM PROTOCOLO

MYPickerViewController ViewController

cancelPickerViewController: (opcional)pickerViewController:pickedItem:

MYPickerViewControllerDelegate

delegatereferência

EXEMPLO - COM PROTOCOLO

Prós:

• Contrato explícito

• Com autocomplete

• Com ajuda do compilador

•Mais flexível e poderoso

Contras:

•Mais trabalho

Com @optional:

• Sem implementações desnecessárias, adapters

• Continua autocomplete!

EXEMPLO - COM BLOCOS

(MYPickerViewController.h)

@property (copy, atomic) void (^cancelBlock) (MYPickerViewController *pickerViewController);

@property (copy, atomic) void (^successBlock) (MYPickerViewController *pickerViewController, NSInteger itemIndex);

EXEMPLO - COM BLOCOS

(MYPickerViewController.m)

- (IBAction)cancelPicking:(id)sender{ if (self.cancelBlock) { self.cancelBlock(self); }}

- (IBAction)confirmPicking:(id)sender{ if (self.successBlock) { self.successBlock(self, self.selectedItem); }}

EXEMPLO - COM BLOCOS

(ViewController.m)

MYPickerViewController *pickerViewController = [[MYPickerViewController alloc] init]; pickerViewController.cancelBlock = ^(MYPickerViewController *pickerViewController) { [self dismissViewControllerAnimated:YES completion:nil]; }; pickerViewController.successBlock = ^(MYPickerViewController *pickerViewController, NSInteger itemIndex) { NSLog(@"Item selecionado: %ld", (unsigned long)itemIndex);

[self dismissViewControllerAnimated:YES completion:nil]; };

[self presentViewController:pickerViewController animated:YES completion:nil];

EXEMPLO - COM BLOCOS

MYPickerViewController ViewController

void (^cancelBlock)(MYPickerViewController *pickerViewController);void (^successBlock)(MYPickerViewController *pickerViewController, NSInteger itemIndex);

Contrato está na assinatura do bloco!

blocobloco (cópia)

EXEMPLO - COM BLOCOS

Prós:

• Contrato explícito

• Com ajuda do compilador

• (Ainda) mais flexível e poderoso

Contras:

• Uma propriedade por callback

• Sintaxe bizarra!

• Problemas de gerenciamento de memória...

EXEMPLO - COM BLOCOS

•Dá pra melhorar um pouquinho a sintaxe...

(MYPickerViewController.h)

typedef void (^MYPickerViewControllerCancelBlock) (MYPickerViewController *pickerViewController);

typedef void (^MYPickerViewControllerSuccessBlock) (MYPickerViewController *pickerViewController, NSInteger itemIndex);

@property (copy, atomic) MYPickerViewControllerCancelBlock cancelBlock;@property (copy, atomic) MYPickerViewControllerSuccessBlock successBlock;

EXEMPLO - COM BLOCOS

• Cuidado com ciclos de retenção!

MYPickerViewController ViewController

blocobloco (cópia de self - “strong”)

picker

pickerViewController (strong)

EXEMPLO - COM BLOCOS

Cuidado:

• Fechamento (closure) no escopo da instância

• Programação funcional - paradigma misto

• Extensão da linguagem C, ainda não padronizada

Curiosidade:

• Sintaxe é a mesma de ponteiro de função (“*” vira “^”)

EXEMPLO - COM BLOCOS

• Resolvendo (possíveis) ciclos de retenção:

(ViewController.m)

typeof(self) __weak weakSelf = self;

pickerViewController.cancelBlock = ^(MYPickerViewController *pickerViewController) { [weakSelf dismissViewControllerAnimated:YES completion:nil]; }; pickerViewController.successBlock = ^(MYPickerViewController *pickerViewController, NSInteger itemIndex) { NSLog(@"Item selecionado: %ld", (unsigned long)itemIndex);

[weakSelf dismissViewControllerAnimated:YES completion:nil]; };

DICAS

• Procure entender o conceito (callback...?)

•Observe as APIs e como elas utilizam o padrão

•Na dúvida, implemente com protocolos (tradicional)

• APIs novas usam cada vez mais blocos - tendência

OBRIGADO!

slideshare.net/osnipso/ios-delegates-mobile-conf-rio-2014

github.com/osnipso/mobileconf2014

osni.oliveira@caelum.com.br

@osnipso