02 Fev, 2012 13:18
Blocos de código em Objective-C
Introdução
Para contextualizar, veja os dois exemplos de utilização de bloco de código. No primeiro exemplo, vamos chamar o método do animateWithDuration:animations: da classe UIView:
CGRect novoFrame = CGRectMake(176.0, 258.0, 72.0, 96.0);
[UIView animateWithDuration:2.0
animations:^ {
self.view.alpha = 1.0;
self.view.frame = novoFrame;
self.view.transform = CGAffineTransformMakeRotation(M_PI);
}
];
Nesse caso, quando a animação for chamada, três transformações serão efetuadas: o alpha, o frame e a rotação de 180 graus na view. Perceba que não há nenhum parâmetro sendo passado para o bloco, e que é possível utilizar variáveis criadas fora do bloco, desde que o escopo permita isso. Além disso, é possível utilizar propriedades da instância da classe onde está o código.
Já no segundo, vamos chamar o método enumerateObjectsUsingBlock: da classe NSArray:
NSArray *nomes =
[NSArray arrayWithObjects:
@"Afonso", @"Felipe",
@"Hildi", @"Karin",
@"Quintana" nil];
[nomes enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
NSLog(@"%@ nome na posição %d", object, index);
}];
Já explico melhor como esse bloco funciona. Por hora, perceba que ele recebe três parâmetros. Olhando a documentação, sabemos que o bloco de código é executado para cada um dos elementos do NSArray. O primeiro parâmetro, object, é um dos elementos da coleção. A segunda variável (index) armazena o índice de object no array. E o terceiro parâmetro (um ponteiro para uma variável boolean) serve para ser utilizado dentro do bloco caso você queira parar a enumeração dos itens.
Uma vez explicado (bem por alto, reconheço) o modo como utilizar os blocos, vamos mostrar como funciona a sintaxe deles.
Sintaxe básica
Como explicado anteriormente, um bloco é simplesmente um conjunto de código executável. Neste exemplo mais simples,
^ {
NSDate *data = [NSDate date];
NSLog(@"A data e a hora agora é %@", data);
};
o acento circunflexo inicia o bloco, enquanto as chaves delimitam o corpo do bloco. Nesse caso, temos um bloco se comportando como um método anônimo.
Mas, sendo anônimo, como utilizar esse bloco? A maneira mais comum é a do primeiro exemplo (animação da view), em que eu passo o bloco como parâmetro, que, obviamente, é um bloco anônimo. Outra maneira de utilizar o bloco é associá-lo a uma variável e então chamar a variável. Veja como ficaria o código anterior:
void (^agora)(void) = ^ {
NSDate *data = [NSDate date];
NSLog(@"A data e a hora agora é %@", data);
};
Agora sim a sintaxe ficou um pouco mais complexa. Veja a imagem abaixo para entender como o bloco deve ser declarado:
Como você pode perceber, o nome do bloco é sempre declarado entre parêntesis. No nosso exemplo, a variável agora pode ser atribuída a blocos que não tenham retorno (o primeiro void) e que não tenham parâmetro (o segundo void). Para executar o código dentro do bloco, basta chamar:
agora();
Olhando o exemplo da animação da UIView, caso eu quiséssemos passar o bloco agora para o método bastaria fazer:
[UIView animateWithDuration:2.0 animations:agora];
Parâmetros para o bloco
Como toda função que se preze, um bloco pode receber parâmetros. Imagine um bloco que, dado um inteiro, retorna esse número ao quadrado. Declarando um bloco anônimo, temos o seguinte:
^(int numero) {
return numero * numero;
};
agora, associando a uma variável, temos:
int (^quadrado)(int) = ^(int numero) {
return numero * numero;
};
e fazendo a associação anterior:
Para utilizar a variável, nada mais simples:
int q = quadrado(8); //q tem valor 64
Nesse caso, só há um parâmetro inteiro. Para outros parâmetros, basta separar os tipos deles por vírgula. Um bloco de método que multiplica duas variáveis ficaria assim:
int (^multiplicar)(int, int) = ^(int a, int b) {
return a * b;
};
E, obviamente, a variável pode ser chamada da seguinte forma:
int x = multiplicar(2,3); //x tem valor 6
Enfim, espero que essa breve (nem tão breve assim) introdução sobre blocos tenha ajudado. Para um maior aprofundamento, vale a pena dar uma lida na documentação da Apple sobre o assunto. Qualquer dúvida, manda aí nos comentários.