Atualizando a Interface Gráfica durante um processo demorado no iOS

by José Antonio on 25/12/2011

Já faz algum tempo que não colocamos uma dica de Objective-C aqui no Zeletron. Deixo abaixo uma dica legal.

Indicar que um processo demorado está sendo executado e que o aplicativo não está travado é uma das indicações do HIG (Human Interface Guidelines) do iOS. Para isso existem indicadores de atividade e barras de progresso, que indicam ao usuário que o programa está em execução ou o quanto falta para terminar a tarefa (no caso do ProgressView).

Activity Indicator

Activity Indicator

Progress View

Progress View

O problema é que qualquer alteração na interface gráfica precisa ser feita na Thread principal do programa e, se o processo demorado está rodando na thread principal, você vai ter problemas para atualizar um ProgressView ou mostrar um ActivityIndicator.

A dica é simples, você separa o código demorado numa thread em background e, sempre que precisar atualizar a interface gráfica, manda o programa fazer isso na thread principal. Assim, ó:

//Evento de um botão de "salvar"
- (IBAction)eventoBotaoSalvar:(id)sender {
    //Manda salvar numa thread em background
    [NSThread detachNewThreadSelector:@selector(salvaUmMonteDeCoisas) 
                             toTarget:self 
                           withObject:nil];
}
 
//--------------------------------------------------
//Dois métodos simples que atualizam a interface gráfica
//--------------------------------------------------
//Mostra o Activity Indicator
- (void)mostraActivityIndicator{
    self.meuActivityIndicator.hidden = NO;
}
 
//Esconde o Activity Indicator
- (void)escondeActivityIndicator{
    self.meuActivityIndicator.hidden = YES;
}
//--------------------------------------------------
 
//Salva a tralha toda
- (void)salvaUmMonteDeCoisas{
    //Mostra o ActivityIndicator antes de começar
    [self performSelectorOnMainThread:@selector(mostraActivityIndicator) 
                           withObject:nil 
                        waitUntilDone:NO];
 
    //Salva tudo (pode demorar à vontade)
    for (NSDictionary *d in meuArrayDeDicionarios){
        [self salvaDicionario:d];
    }
 
    //Depois de terminar tira o ActivityIndicator
    [self performSelectorOnMainThread:@selector(escondeActivityIndicator) 
                           withObject:nil 
                        waitUntilDone:NO];
}

Dessa forma, o programa não fica travado enquanto você está salvando aquele monte de dados. Você pode, inclusive, criar o ActivityIndicator na status bar do aparelho e deixar o usuário fazer outras coisas enquanto o App está salvando.

O código acima é só um exemplo de como podemos usar o detachNewThreadSelector e o performSelectorOnMainThread. Você pode encontrar, eventualmente, erros de sintaxe nele, mas a ideia é essa: Manda executar uma tarefa demorada em background e, sempre que precisar, atualiza a interface na thread principal.


Poderoso Copão

Comments on this entry are closed.

Previous post:

Next post: