Trabalhando com blocos
Uma das mais poderosas e recentes adições no Objective-C é a inclusão de um recurso conhecido como blocos. Veremos como isso funciona.
Essencialmente, um bloco permite que você defina uma função de um objeto em linha de código. Essas funções do objeto podem ser referenciadas usando variáveis tradicionais. Isso significa que podemos definir pedaços reutilizáveis de código que funcionam e que podem ser passados apenas como objetos que permitem que o código seja executado dentro de outros objetos, dinamicamente. Isso pode parecer confuso, mas ao vermos isso mais adiante, o conceito ficará mais claro.
Declarando Blocos
Nesta sessão, veremos o que é um bloco em Objective-C. Abaixo, uma amostra de um bloco simples.
int main (int argc, const char * argv[ ])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
void (^myBlock) (NSString) *x);
myBlock = ^(NSString *x)
{
NSLog(@"%@", x);
};
[pool drain];
return 0;
}
Um bloco, em sua essência, é uma variável como qualquer outra. O que faz blocos ser diferente é que os dados armazenados dentro do bloco são o corpo de uma função. Ao utilizar um bloco, podemos chamar a função, tal como uma outra função padrão, passando-lhe argumentos e recebendo um valor de retorno.
No caso deste código, a variável que contém o bloco é chamada de "myBlock". Primeiro, foi declarada a variável com a linha vazia (^myBlock) (NSString *). Variáveis normais, quando declaradas são relativamente simples. Essas, não precisam ter argumentos passados pra elas, nem retornam valores. Um bloco, por outro lado, é armazenado em uma variável, não possui argumentos e tipo de retorno declarados. Portanto, a sua declaração é um pouco mais complexa do que a de uma variável normal.
Uma declaração de bloco consiste em seu tipo de retorno (neste caso, void). O tipo de retorno do bloco é colocado no lugar onde normalmente esperamos ver a definição do tipo de variável que está sendo declarada. Em uma declaração de bloco, no entanto, estamos declarando o tipo de valor que será devolvido a partir do bloco quando ele é executado.
Após a definição do tipo de retorno, há um operador essencial que é usado pra dizer ao compilador que estamos definindo um bloco, ao invés de outro tipo de variável. Este operador é o caractere ^.
Podemos pensar nisso como sendo mais fácil declarar um ponteiro. Assim como quando se declara uma variável ponteiro o caractere * é usado para indicar que a variável em questão é um ponteiro. No caso do bloco, usamos o caractere ^. Seguindo o caractere ^, o nome da variável que armazena o bloco (myBlock). Este nome vem entre parênteses para separa-los dos seus argumentos depois.
O nome da variável segue as mesmas convenções de nomes de variáveis do resto da linguagem, que deve conter apenas caracteres alfanuméricos e não podem começar com números.
Após o fechamento dos parênteses do bloco com o nome da variável, os argumentos que precisam ser passados para o bloco quando ele é usado, são separados por vírgulas e incluem um conjunto adicional de parênteses (aqui, este é (NSString *)). Ao listar estes argumentos, precisamos fornecer os nomes das variáveis. Se o fizer, é com você, mas não é necessário. Uma boa maneira de pensar sobre isso é que não estamos realmente declarando o corpo da função neste momento. Portanto, fornecer os nomes das variáveis para os argumentos não serve de nada, porque não será utilizado agora. Ao invés disso, temos simplesmente que dizer ao compilador quais os tipos de argumentos esperar. Basta fornecer os tipos de argumentos separados por vírgulas.
Como sempre, ao terminar uma declaração, utiliza-se o ponto e vírgula. Neste ponto, declaramos uma variável, que pode armazenar um bloco que retorna o tipo de valor que especificamos, e leva os argumentos que também especificamos. Lembrando, o nome dessa variável é myBlock.
Declarar a variável apenas, como sabermos, não é o suficiente. Temos também que armazenar o bloco, a fim de usa-lo. Iniciar uma nova variável com um bloco é tranquilo, usando o operador de atribuição, em seguida, novamente, uma sintaxe especial indicando que estamos criando a variável que irá armazenar o bloco.
Para a definição do bloco, novamente se usa o caractere ^ para dizer ao compilador que o que se segue é a definição do bloco. Podemos omitir o tipo de retorno na definição, já que o compilador pode determinar o tipo de retorno, verificando a variável que está sendo armazenada no bloco. Devemos, no entanto, fornecer a especificação do argumento para o bloco, novamente, dentro de parênteses. Neste caso, devemos também fornecer o nome das variáveis para os argumentos que estão sendo passados. Isso faz sentido, porque estamos declarando o nome das variáveis para os argumentos que serão utilizado dentro do corpo do bloco.
Após o fechamento do parênteses da lista de argumentos, fornecemos em seguida o corpo do bloco. Este corpo de código assume uma forma que é quase idêntico a declaração de uma função. Devemos colocar o código do bloco entre chaves, para executar qualquer outra operação que escolhermos, utilizando os argumentos conforme necessário e retornar o valor apropriado após finalizar. Assim como na definição de uma função padrão, o código dentro de um bloco pode ser distribuído em várias linhas.
Até a próxima!















