Design Pattern para iOS – Parte 2

Continuando a tradução sobre design pattern, esta é a segunda parte.
Este tutorial foi traduzido da página: http://www.raywenderlich.com/46988/ios-design-patterns.
Onde vocês podem consultar a versão em inglês.
Lembrando que esta tradução pode conter erros, e ficarei muito feliz que vocês possam indicar nos comentários, assim como elogios também são vindos 😀

Decorator Design Pattern

O padrão Decorator adiciona dinamicamente comportamentos e responsabilidades a um objeto sem modificar seu código. É uma alternativa para a subclassificação onde você modifica um comportamento de classe por “envolvê-lo” com outro objeto.

Em Objective-C, há duas implementações muito comuns deste padrão: Categoria e Delegação.

Categoria (Category)

Categoria é um mecanismo extremamente poderoso que permite que você adicione métodos para classes existentes sem subclassificação. Os novos métodos são adicionados ao tempo de compilação e pode ser executado como métodos normais da classe estendida. É um pouco diferente da definição clássica de um decorador, porque a categoria não possui uma instância da classe que se estende.

Nota: além do alargamento de suas próprias classes, você também pode adicionar métodos de suas próprias classes para as classes de Cocoa!

Como Usar Categorias

2-1

Imagine uma situação em que você tem um objeto Album que pretende apresentar dentro de uma visão de tabela:

Para onde irão os títulos dos álbuns que vieram?

Álbum é um objeto Modelo, não importa como você irá apresentar os dados. Você irá precisar de um código externo para adicionar essa funcionalidade para a classe Album, mas sem modificar a classe diretamente.

Você vai criar uma categoria que é uma extensão do Álbum; que vai definir um novo método que devolve uma estrutura de dados que pode ser utilizado facilmente com UITableViews.

A estrutura de dados será parecido com o seguinte:

2-2

Para adicionar uma Categoria ao Album, vá até File\New\File… e selecione Objective-C Catagory – Não selecione Objective-C Class!! Coloque TableRepresentation no campo Category e Album no campo Category On.

Nota: Você notou o nome do novo arquivo? Album + TableRepresentation significa que você está estendendo a classe Album. Esta convenção é importante, porque é mais fácil de ler e evita um choque com outras categorias que você ou alguém poderia criar.

Vá em Album+TableRepresentation.h e adicione o seguinte protótipo de método:

- (NSDictionary *)tr_tableRepresentation;

Observe que há um tr_ no início do nome do método, como uma abreviação do nome da categoria: TableRepresentation. Mais uma vez, convenções como essa vão ajudar a evitar conflitos com outros métodos!

Nota: Se o nome de um método declarado em uma categoria é o mesmo como um método na classe original, ou o mesmo que um método de outra categoria na mesma classe (ou mesmo uma superclasse), o comportamento é indefinido como a que implementação do método é usado em tempo de execução. Isso é menos provável de ser um problema se você estiver usando categorias com suas próprias classes, mas pode causar sérios problemas ao utilizar categorias para adicionar métodos para Cocoa standard ou as classes do Cocoa Touch.

Vá para Album+TableRepresentation.m e adicione o seguinte método:

- (NSDictionary*)tr_tableRepresentation
{
return @{@"titles":@[@"Artist", @"Album", @"Genre", @"Year"],
@"values":@[self.artist, self.title, self.genre, self.year]};
}

Consideremos por um momento o quão poderoso esse padrão pode ser:

– Você está usando as propriedades diretamente do álbum.

– Você adicionou métodos à classe Album, mas você não fez uma subclasse dela. Caso você precise criar uma subclasse de Album, você ainda pode fazer isso também.

– Esta simples adição permite que você retorne uma representação UITableView-ish de um álbum, sem modificar o código do álbum.

A Apple usa muitas Categorias nas classes de Foundation. Para ver como eles fazem isso, abra NSString.h. Encontre @interface NSString, e você vai ver a definição da classe, juntamente com três categorias: NSStringExtensionMethods, NSExtendedStringPropertyListParsing e NSStringDeprecated. Categorias ajudam a manter os métodos organizados e separados em seções.

Delegation

Outro design pattern de Decoration, Delegation, é um mecanismo em que um objecto atua em nome de, ou em coordenação com, outro objeto. Por exemplo, quando você usa a UITableView, um dos métodos que você deve implementar é tableView:numberOfRowInSection:.

Você não pode esperar que o UITableView saiba quantas linhas você quer ter em cada seção, pois isso é específico do aplicativo. Portanto, a tarefa de calcular a quantidade de linhas em cada seção é repassado para o delegado UITableView. Isto permite que a classe UITableView seja independente dos dados que exibe.

Aqui está uma pseudo-explicação do que acontece quando você cria um novo UITableView:

2-3

O objeto UITableView faz o seu trabalho de exibir uma exibição de tabela. No entanto, eventualmente, ele vai precisar de alguma informação que ele não tem. Em seguida, ele se volta para os seus delegates e envia uma mensagem pedindo informações adicionais. Na implementação do padrão delegate em Objective-C, uma classe pode declarar métodos opcionais e necessários através de um protocolo. Você vai cobrir protocolos um pouco mais adiante neste tutorial.

Pode parecer mais fácil simplesmente criar subclasses de um objeto e substituir os métodos necessários, mas considere que você só pode criar subclasses com base em uma única classe. Se você quer um objeto para ser o delegate de dois ou mais objetos, você não será capaz de conseguir isso por subclasses.

Nota: Este é um padrão importante. Apple usa essa abordagem, na maioria das classes UIKit: uitableview, UITextView, UITextField, UIWebView, uialert, UIActionSheet, UICollectionView, UIPickerView, UIGestureRecognizer, UIScrollView. A lista vai sobre e sobre.

Como Usar Delegate Pattern

Vá em ViewController.m e adicione esses import’s no todo do arquivo:

#import “LibraryAPI.h”

#import “Album+TableRepresentation.h”

Agora, adicione estas variáveis ​​privadas para a extensão de classe para que a extensão de classe se parece com isso:

@interface ViewController () {
UITableView *dataTable;
NSArray *allAlbums;
NSDictionary *currentAlbumData;
int currentAlbumIndex;
}

@end

Em seguida, substitua a linha @interface na extensão de classe com esta:

@interface ViewController () <UITableViewDataSource, UITableViewDelegate> {

É assim que você faz o seu delegate em conformidade com um protocolo – pense nisso como uma promessa feita pelo delegate para cumprir o contrato do método. Aqui, você indica que ViewController estará de acordo com os protocolos UITableViewDataSource e UITableViewDelegate. Desta forma UITableView pode estar absolutamente certo de que os métodos necessários são implementadas por seu delegado.

Em seguida, substitua viewDidLoad: com este código:

- (void)viewDidLoad
{
[super viewDidLoad];
//1
self.view.backgroundColor = [UIColor colorWithRed:0.76f green:0.81f blue:0.87f alpha:1];
currentAlbumIndex = 0;

//2
allAlbums = [[LibraryAPI sharedInstance] getAlbums];

//3
//the uitableview that presents the album data
dataTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 120, self.view.frame.size.width, self.view.frame.size.height-120) style:UITableViewStyleGrouped];
dataTable.delegate = self;
dataTable.dataSource = self;
dataTable.backgroundView = nil;
[self.view addSubview:dataTable];
}

Aqui está uma repartição do código acima:

1 – Alterar a cor de fundo para uma cor azul agradável marinha.
2 – Obtêm uma lista de todos os álbuns através da API. Você não usa PersistencyManager diretamente!
3 – Isto é onde você cria o UITableView. Você declara que o view controller é a fonte de UITableView delegate/data source; Portanto, todas as informações exigidas pela UITableView será fornecida pelo view controller.

Agora adicione o seguinte método em ViewController.m

- (void)showDataForAlbumAtIndex:(int)albumIndex
{
// Código de defesa: verifica se o índice solicitado é menor do que a quantidade de álbuns
if (albumIndex < allAlbums.count)
{
// buscar o album
Album *album = allAlbums[albumIndex];
// guardar os dados de álbuns para apresentá-lo mais tarde no tableview
currentAlbumData = [album tr_tableRepresentation];
}
else
{
currentAlbumData = nil;
}

// temos os dados que precisamos, vamos atualizar nossa tableview
[dataTable reloadData];
}

showDataForAlbumAtIndex: busca os dados álbum exigido a partir do array de álbuns. Quando você quer apresentar os novos dados, você só precisa chamar reloadData. Isso faz com que UITableView pergunte ao seu delegate coisas como quantas seções devem aparecer na exibição de tabela, quantas linhas em cada seção, e como cada célula deve ficar.

Adicione a seguinte linha ao final de viewDidLoad:

[self showDataForAlbumAtIndex:currentAlbumIndex];

Isso carrega o álbum atual no execução inicial do aplicativo. E desde que currentAlbumIndex foi previamente definido para 0, isso mostra o primeiro álbum na coleção.

Crie e execute o seu projeto; você vai experimentar uma falha com a seguinte exceção exibida no console de depuração:

2-4

“-[ViewCotroller tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x8a9d8e0”

O que está acontecendo aqui? Você declarou que ViewController como delegate e os dados de origem do UITableView. Mas ao fazer isso, você deve estar de acordo com todos os métodos necessários – incluindo tableView: numberOfRowsInSection: – que você não fêz ainda.

Adicione o seguinte código para ViewController.m em qualquer lugar entre as linhas @implementation e end:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [currentAlbumData[@"titles"] count];
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"];
}

cell.textLabel.text = currentAlbumData[@"titles"][indexPath.row];
cell.detailTextLabel.text = currentAlbumData[@"values"][indexPath.row];

return cell;
}

tableView: numberOfRowsInSection: retorna o número de linhas a serem exibidas na exibição de tabela, o que corresponde ao número de títulos na estrutura de dados.

tableView: cellForRowAtIndexPath: cria e retorna uma célula com o título e seu valor.

Crie e execute o seu projeto. Seu aplicativo deve iniciar e apresentá-lo com a seguinte tela:

2-5

As coisas estão visualmente muito boas até agora. Mas se você se lembra da primeira imagem que mostra o app acabado, onde tem um scroller horizontal na parte superior da tela para alternar entre álbuns. Em vez de codificar um objectivo único scroller horizontal, por que não torná-lo reutilizável para qualquer view?

Para tornar esta visão reutilizável, todas as decisões sobre o seu conteúdo devem ser deixados para outro objeto: um delegado. O scroller horizontal deve declarar métodos que seu delegate implementa a fim de trabalhar com o scroller, semelhante à forma como os métodos UITableView delegate trabalha. Vamos implementar isso quando discutimos o próximo padrão de design.

Adapter Pattern

Um Adapter permite que classes com interfaces incompatíveis trabalhem em conjunto. Ele envolve-se em torno de um objeto e expõe uma interface padrão para interagir com esse objeto.

Se você estiver familiarizado com o padrão Adapter, então você vai notar que a Apple o implementa de uma forma um pouco diferente – a Apple usa protocolos para fazer o trabalho. Você pode estar familiarizado com protocolos como UITableViewDelegate, UIScrollViewDelegate, NSCoding e NSCopying. Como um exemplo, com o protocolo NSCopying, qualquer classe poderá fornecer um método de cópia normal.

Como Usar Adapter Pattern

O scroller horizontal mencionado anteriormente será parecido com este:

2-6

Para começar a implementá-lo, clique no grupo View no Project Navigator, selecione New File … e crie uma classe com o modelo de classe iOS\Cocoa Touch\Objective-C. O nome da classe nova será HorizontalScroller, e será subclasse de UIView.

Abra HorizontalScroller.h e insira o seguinte código após a linha @end:

@protocol HorizontalScrollerDelegate <NSObject>
// methods declaration goes in here
@end

Isso define um protocolo chamado HorizontalScrollerDelegate, que herda o protocolo NSObject, da mesma forma que uma classe Objective-C herda de seu pai. É uma boa prática em conformidade com o protocolo NSObject – ou para corresponder a um protocolo que se está em conformidade com o protocolo NSObject. Isso permite que você envie mensagens definidas por NSObject ao delegate de HorizontalScroller. Em breve você verá por que isso é importante.

Você define os métodos necessários e opcionais que o delegate irá implementar entre as linhas @protocol e @end. Então, adicione os seguintes métodos de protocolo:

@required
// perguntar ao delegate quantas views ele quer apresentar dentro do scroller horizontal
-(NSInteger)numberOfViewsForHorizontalScroller:(HorizontalScroller*)scroller;

// solicita ao delegate para retornar a view que deve aparecer em <index>- (UIView*)horizontalScroller:(HorizontalScroller*)scroller viewAtIndex:(int)index;

// iinformar ao delegate que a view em <index> foi clicada
- (void)horizontalScroller:(HorizontalScroller*)scroller clickedViewAtIndex:(int)index;

@optional
// solicita ao delegate do index da view inicial para mostrar. Este método é opcional

// eo padrão é 0 se não for implementada pelo delegate
- (NSInteger)initialViewIndexForHorizontalScroller:(HorizontalScroller*)scroller;

Aqui você tem ambos os métodos necessários e opcionais. Métodos necessários devem ser implementados pelo delegate e geralmente contêm alguns dados que é absolutamente necessário pela classe. Neste caso, os detalhes necessários são o número de views, a view em um índice específico, bem como o comportamento quando a view é aproveitado. O método opcional aqui é a initial view; se não for implementada, então o HorizontalScroller será o padrão para o primeiro índice.

Em seguida, você vai precisar se referir a seu novo delegate a partir da definição de classe HorizontalScroller. Mas a definição do protocolo é a seguir a definição de classe e por isso não é visível neste ponto. O que você pode fazer?

A solução é encaminhar a declaração do protocolo para que o compilador (e Xcode) saiba que tal protocolo estará disponível. Para fazer isso, adicione o seguinte código acima da linha @interface:

@protocol HorizontalScrollerDelegate;

Ainda em HorizontalScroller.h, adicione o seguinte código entre as declarações @interface e @end:

@property (weak) id<HorizontalScrollerDelegate> delegate;

- (void)reload;

O atributo da propriedade que você criou acima é definido como fraco. Isto é necessário para evitar que um ciclo de retain. Se uma classe mantém um ponteiro forte para seu delegate e o delegate mantém um ponteiro forte para a classe que está em conformidade, seu aplicativo irá vazar memória já que nem a classe irá liberar a memória alocada para o outro.

O id significa que a delegate só pode ser atribuído classes que estejam em conformidade com HorizontalScrollerDelegate, dando-lhe algum tipo de segurança.

O método reload é modelado após reloadData em UITableView; ele recarrega todos os dados utilizados para construir o scroller horizontal.

Substitua o conteúdo do HorizontalScroller.m com o seguinte código:

#import "HorizontalScroller.h"

// 1
#define VIEW_PADDING 10
#define VIEW_DIMENSIONS 100
#define VIEWS_OFFSET 100

// 2
@interface HorizontalScroller () <UIScrollViewDelegate>
@end

// 3
@implementation HorizontalScroller
{
UIScrollView *scroller;
}

@end

Tomando cada bloco de comentário, por sua vez:

1- Define constantes para tornar mais fácil para modificar o layout na hora do design. As dimensões da View interna do scroller será de 100 x 100 com uma margem de 10 pontos de seu retângulo delimitador.

2 – HorizontalScroller está em conformidade com o protocolo UIScrollViewDelegate. Uma vez que HorizontalScroller usa um UIScrollView para percorrer as capas de álbuns, ele precisa saber dos eventos do usuário, tais como quando um usuário para o scrolling.

3 – Criar a exibição de rolagem contendo qs Views.

Em seguida, você precisa implementar o inicializador. Adicionar o seguinte método:

- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
scroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
scroller.delegate = self;
[self addSubview:scroller];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scrollerTapped:)];
[scroller addGestureRecognizer:tapRecognizer];
}
return self;
}

A exibição de rolagem preenche completamente o HorizontalScroller. A UITapGestureRecognizer detecta toques na exibição de rolagem e verifica se uma capa de álbum foi escolhido. Se for assim, ele notifica delegate HorizontalScroller.

Agora adicione este método:

- (void)scrollerTapped:(UITapGestureRecognizer*)gesture {

  CGPoint location = [gesture locationInView:gesture.view];

    // Nós não podemos usar um enumerador aqui, porque não quero
    // enumerar TODAS as subvisualizações de UIScrollView.
    // Queremos enumerar apenas as subvisualizações que adicionamos

     for (int index=0; index<[self.delegate numberOfViewsForHorizontalScroller:self]; index++) {

      UIView *view = scroller.subviews[index];
      if (CGRectContainsPoint(view.frame, location)){

          [self.delegate horizontalScroller:self clickedViewAtIndex:index];
          [scroller setContentOffset:CGPointMake(view.frame.origin.x - self.frame.size.width/2 + view.frame.size.width/2, 0) animated:YES];

break;
         }
     }
 }

O gesto passado como um parâmetro permite extrair a localização via locationInView :.

Em seguida, você invoca numberOfViewsForHorizontalScroller: no delegate. A instância HorizontalScroller não tem informações sobre delegate que não sabe que pode enviar com segurança essa mensagem, desde que o delegate esteja de acordo com o protocolo HorizontalScrollerDelegate.

Para cada view na exibição do scroller, faça um teste de hit(toque) usando CGRectContainsPoint para encontrar a view que foi escolhida(tocada). Quando a view for encontrada, então envia o delegate a horizontalScroller: clickedViewAtIndex: mensagem. Antes de sair do loop for, centraliza a visão escolhida na exibição de rolagem.

Agora, adicione o seguinte código para recarregar o scroller:

- (void)reload
{
// 1 - Não carregará nada se não há delegate
if (self.delegate == nil) return;

// 2 - remove todas subviews
[scroller.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[obj removeFromSuperview];
}];

// 3 - xValue é o ponto inicial das views dentro de do scroller   CGFloat xValue = VIEWS_OFFSET;
for (int i=0; i<[self.delegate numberOfViewsForHorizontalScroller:self]; i++)
{
// 4 - adicionar uma view na posição correta

xValue += VIEW_PADDING;
UIView *view = [self.delegate horizontalScroller:self viewAtIndex:i];
view.frame = CGRectMake(xValue, VIEW_PADDING, VIEW_DIMENSIONS, VIEW_DIMENSIONS);
[scroller addSubview:view];
xValue += VIEW_DIMENSIONS+VIEW_PADDING;
}

// 5
[scroller setContentSize:CGSizeMake(xValue+VIEWS_OFFSET, self.frame.size.height)];

// 6 - se uma visão inicial é definida, centraliza a scroller nele
if ([self.delegate respondsToSelector:@selector(initialViewIndexForHorizontalScroller:)])
{
int initialView = [self.delegate initialViewIndexForHorizontalScroller:self];
[scroller setContentOffset:CGPointMake(initialView*(VIEW_DIMENSIONS+(2*VIEW_PADDING)), 0) animated:YES];
}
}

Percorrendo o código comment-by-comentário:

1 – Se não há delegate, então não há nada a ser feito e você pode retornar.

2 – Remove todos as subvisualizações previamente adicionadas à exibição de rolagem.

3 – Todas as Views são posicionados a partir do offset fornecido. Actualmente, é de 100, mas pode ser facilmente ajustado, alterando a #DEFINE no topo do ficheiro.

4 – O HorizontalScroller pergunta ao seu delegate pela view, um de cada vez e coloca-os lado a lado ao outro na horizontal com o preenchimento previamente definido.

5 – Uma vez que todos as Views estão no lugar, defini o conteúdo de deslocamento para a view de rolagem para permitir que o usuário navegue através de todos os álbuns.

6 – O HorizontalScroller verifica se o seu delegate responde ao initialViewIndexForHorizontalScroller: selector. Esta verificação é necessária porque esse método determinado protocolo é opcional. Se o delegate não implementar este método, 0 é usado como o valor padrão. Finalmente, este pedaço de código define a exibição de rolagem para centralizar a visão inicial definido pelo delegado.

Você executa reload quando seus dados mudam. Você também precisa chamar esse método quando você adiciona HorizontalScroller para outra view. Adicione o seguinte código para HorizontalScroller.m para cobrir o último cenário:

- (void)didMoveToSuperview
{
[self reload];
}

A mensagem didMoveToSuperview é enviado para uma view quando ela é adicionada a outra view como um subexibição. Este é o momento certo para recarregar o conteúdo do scroller.

A última peça do quebra-cabeça HorizontalScroller é certificar-se que o álbum que você está vendo é sempre centrada no interior da exibição de rolagem. Para fazer isso, você vai precisar realizar alguns cálculos quando o usuário arrasta a view de rolagem com o dedo.

Adicione o seguinte método (de novo para HorizontalScroller.m):

- (void)centerCurrentView
{
int xFinal = scroller.contentOffset.x + (VIEWS_OFFSET/2) + VIEW_PADDING;
int viewIndex = xFinal / (VIEW_DIMENSIONS+(2*VIEW_PADDING));
xFinal = viewIndex * (VIEW_DIMENSIONS+(2*VIEW_PADDING));
[scroller setContentOffset:CGPointMake(xFinal,0) animated:YES];
[self.delegate horizontalScroller:self clickedViewAtIndex:viewIndex];
}

O código acima leva em consideração o deslocamento da exibição de rolagem e as dimensões eo preenchimento das views atual, a fim de calcular a distância da view atual do centro. A última linha é importante: uma vez que a view é centrada, você, então, informa ao delegate que o modo de exibição selecionado mudou.

Para detectar se o usuário terminou arrastando dentro da exibição de rolagem, você deve adicionar os seguintes métodos UIScrollViewDelegate:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate)
{
[self centerCurrentView];
}
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self centerCurrentView];
}

scrollViewDidEndDragging: willDecelerate: informa ao delegate quando o usuário terminou de arrastar. O parâmetro desacelerar é verdadeiro se a exibição de rolagem não chegou a parar por completo ainda. Quando a ação de rolagem termina, o sistema chama scrollViewDidEndDecelerating. Em ambos os casos, deve chamar o novo método para centralizar a view atual uma vez que a view atual, provavelmente, mudou depois que o usuário arrastou a exibição de rolagem.

Sua HorizontalScroller está pronto para uso! Navegue através do código que você acabou de escrever; você vai ver não há uma única menção das classes Álbum ou AlbumView. Isso é excelente, porque isto significa que o novo scroller é verdadeiramente independente e reutilizável.

Build o seu projeto para se certificar que tudo compila corretamente.

Agora que HorizontalScroller estiver concluída, é hora de usá-lo em seu aplicativo. Abra ViewController.m e adicione as seguintes importações:

#import "HorizontalScroller.h"
#import "AlbumView.h"

Adicione HorizontalScrollerDelegate aos protocolos que ViewController está em conformidade :

@interface ViewController ()<UITableViewDataSource, UITableViewDelegate, HorizontalScrollerDelegate>

Adicione a seguinte variável de instância para o Horizontal Selecionador para a extensão de classe:

HorizontalScroller *scroller;

Agora você pode implementar os métodos do delegate; você ficará espantado em como apenas algumas linhas de código pode executar uma série de funcionalidades.

Adicione o seguinte código para ViewController.m:

#pragma mark - HorizontalScrollerDelegate methods
- (void)horizontalScroller:(HorizontalScroller *)scroller clickedViewAtIndex:(int)index
{
currentAlbumIndex = index;
[self showDataForAlbumAtIndex:index];
}

Isso define a variável que armazena o álbum atual e depois chama showDataForAlbumAtIndex: para exibir os dados para o novo álbum.

Nota: É uma prática comum colocar métodos que se encaixam depois de uma directiva marca #pragma. O compilador irá ignorar esta linha, mas se você usar o drop down a lista de métodos em seu arquivo atual através da barra de salto do Xcode, você verá um separador e um título em negrito para a directiva. Isso ajuda você a organizar seu código para facilitar a navegação no Xcode.

Em seguida, adicione o seguinte código:

- (NSInteger)numberOfViewsForHorizontalScroller:(HorizontalScroller*)scroller
{
return allAlbums.count;
}

Isso, como você vai reconhecer, é o método de protocolo de retornar a quantidade de views para a exibição de rolagem. Uma vez que a view de rolagem irá exibir capas de todos os dados do álbum, a contagem é o número de registros de álbuns.

Agora, adicione o seguinte código:

- (UIView*)horizontalScroller:(HorizontalScroller*)scroller viewAtIndex:(int)index
{
Album *album = allAlbums[index];
return [[AlbumView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) albumCover:album.coverUrl];
}

Aqui você cria um novo AlbumView e o passa para o HorizontalScroller.

É isso aí! Apenas três métodos curtos para mostrar uma ótima scroller horizontal.

Sim, você ainda precisa realmente criar o scroller e adicioná-lo à sua tela principal, mas antes de fazer isso, adicione o seguinte método:

- (void)reloadScroller
{
allAlbums = [[LibraryAPI sharedInstance] getAlbums];
if (currentAlbumIndex &lt; 0) currentAlbumIndex = 0;
else if (currentAlbumIndex &gt;= allAlbums.count) currentAlbumIndex = allAlbums.count-1;
[scroller reload];

[self showDataForAlbumAtIndex:currentAlbumIndex];
}

Este método carrega dados do álbum via LibraryAPI e define a view atualmente exibida com base no valor atual do índice de exibição atual. Se o índice de view atual é menor que 0, o que significa que nenhuma view foi selecionado, em seguida, o primeiro álbum da lista é exibida. Caso contrário, o último álbum é exibido.

Agora, inicialize o scroller, adicionando o seguinte código para viewDidLoad antes de [self showDataForAlbumAtIndex: 0];:

scroller = [[HorizontalScroller alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 120)];
scroller.backgroundColor = [UIColor colorWithRed:0.24f green:0.35f blue:0.49f alpha:1];
scroller.delegate = self;
[self.view addSubview:scroller];
[self reloadScroller];

O código acima simplesmente cria uma nova instância de HorizontalScroller, define a cor de fundo e delegate, acrescenta o scroller à view principal, em seguida, carrega os subvisualizações para o scroller para exibir os dados do álbum.

Nota: Se um protocolo torna-se muito grande e é embalado com uma série de métodos, você deve considerar dividi-lo em vários protocolos menores. UITableViewDelegate e UITableViewDataSource são um bom exemplo, já que são os dois protocolos de UITableView. Tentar projetar seus protocolos para que cada um trate uma área específica de funcionalidade.

Build e execute o seu projeto e vejam o seu novo scroller horizontal incrível:

2-7

Ah, espere. O scroller horizontal está em em seu lugar, mas onde estão as capas?

Ah, isso esta certo – você não implementará o código para baixar as capas ainda. Para fazer isso, você vai precisar adicionar uma maneira de baixar as imagens. Uma vez que todo o seu acesso aos serviços passa por LibraryAPI, é aí que este novo método teria que passar. No entanto, há algumas coisas a considerar em primeiro lugar:

1 – AlbumView não deve trabalhar diretamente com LibraryAPI. Você não quer misturar view da lógica com a lógica de comunicação.

2 – Pela mesma razão, LibraryAPI não deve saber sobre AlbumView.

3 – LibraryAPI precisa informar AlbumView uma vez que as capas são baixados desde que AlbumView tenha as capas para exibir.

Soa como um enigma? Não se desespere, você vai aprender como fazer isso usando o padrão Observer! 🙂

Acompanhe a terceira parte do Tutorial no link: Design Pattern para iOS – Parte 3

Anúncios

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s