View
391
Download
4
Category
Preview:
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/
Citation preview
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
Recommended