09 Fev, 2011 18:00

Dicas para ajudar a depurar o código em Objective-C

Nesse post recolhemos algumas dicas úteis que utilizamos em nossos projetos. Vale lembrar que a maioria delas já está disponível na internet, o que fizemos foi juntá-los aqui.

Melhorias no Log

Para aqueles que usam e abusam do NSLog, devem sempre ter em mente que ele sai no console do aparelho. Ou seja, vai que você esquece de apagar aquele NSLog que escreve algo que o usuário não deveria saber. Aí, basta que o usuário tenha o Xcode ou o iPhone Configuration Utility, e - que beleza! - está lá a informação que voce não deveria mostrar.

Output no console

Outro ponto que alguns desenvolvedores reclamam é de ter sempre que usar texto formatado no NSLog. Os que vieram de Java provavelmente sentem saudades do System.out.println(), que, embora verborrágico, ao menos permitia colocar lá o objeto que quisesse, e funcionava.

Por conta disso, criamos algumas diretivas no Prefix.pch para facilitar nossa vida. Veja o código a seguir:

#ifdef DEBUG

#define myLog(format, ...) NSLog(@"%s:%@", __PRETTY_FUNCTION__,[NSString stringWithFormat:format, ## __VA_ARGS__]);
#define myLogD(obj) NSLog(@"%s:%@", __PRETTY_FUNCTION__,[NSString stringWithFormat:@"%@", obj]);
#define myLogI(myint) NSLog(@"%s:%@", __PRETTY_FUNCTION__,[NSString stringWithFormat:@"%d", myint]);
#define myLogF(myfloat) NSLog(@"%s:%@", __PRETTY_FUNCTION__,[NSString stringWithFormat:@"%f", myfloat]);
#define MARK    myLog(@"");

#else

#define myLog(format,...)
#define myLogD(obj)
#define myLogI(myint)
#define myLogF(myfloat)
#define MARK

#endif

A gente criou o myLog(), que substitui o NSLog do Objective-C. Perceba que o #ifdef inicial distingue o comportamento do método para distribuição dos outros modos. Em distribuição, o myLog() não faz nada. Já nas outras configurações ele joga no output o resultado do método NSLog. Isso só funciona porque ao criar um projeto o Xcode já cria uma variável chamada DEBUG:

Variável de Debug no Xcode

Percebeu que ele tem um __PRETTY_FUNCTION__ no método? Pois é, isso serve para imprimir também o nome do método de onde o myLog() foi chamado. Mais uma facilidade que ajuda muito na hora de ver o valor no output.

Depois disso, temos mais três métodos:

#define myLogD(obj) NSLog(@"%s:%@", __PRETTY_FUNCTION__,[NSString stringWithFormat:@"%@", obj]);
#define myLogI(myint) NSLog(@"%s:%@", __PRETTY_FUNCTION__,[NSString stringWithFormat:@"%d", myint]);
#define myLogF(myfloat) NSLog(@"%s:%@", __PRETTY_FUNCTION__,[NSString stringWithFormat:@"%f", myfloat]);

O primeiro, o myLogD(), serve para exibir a descrição de um objeto. Digamos que você tenha um objeto cliente. Basta utilizar o método dessa forma:

myLogD(cliente);

e ele imprime na tela a descrição dele. O segundo e o terceiro servem para variáveis inteiras e de ponto flutuante.

E tem o último método, o MARK. Lembra das vezes em que você teve que depurar, e queria saber se um método era chamado na execução do programa? Em tempos antigos você utilizaria NSLog(@"passei no método conectar()"), ou algo semelhante. Pois bem, com o MARK, basta escrever MARK no código, e ele imprime o nome do método na saída. Simples, não?

O temido EXC_BAD_ACCESS

De todos os erros genéricos que o Objective-C pode te mostrar, um dos piores é o EXC_BAD_ACCESS. O EXC_BAD_ACCESS é lançado quando o programa tenta enviar uma mensagem (por exemplo, a chamada de um método) para um objeto que já foi liberado (released). Na maioria das vezes, quando o erro é detectado, a pilha de processos onde o objeto estava já se foi, o que dificulta descobrir onde o erro realmente aconteceu.

Mas há uma solução que na maioria dos casos consegue mapear qual objeto foi liberado: basta utilizar a variável de ambiente NSZombieEnabled. Com ela, o Objective-C deixa alocado na memória um objeto dummy, guardando a referência. Quando acontece o EXC_BAD_ACCESS, ele retorna o objeto e a mensagem que foi enviada para ele.

Para habilitar essa variável é bem simples: na seção 'Executables', clique duas vezes no executável do seu projeto. Na aba 'Arguments', na seção 'Variables to be set in the enviroment', adicione a variável NSZombieEnabled, dando o valor YES para ela. Para habilitar, basta marcar o check a esquerda.

NSZombieEnabled

Vale chamar a atenção para um detalhe: como o NSZombieEnabled é um recurso que guarda na memória os objetos que foram liberados, tenha em mente que ela é um auxílio para testes, e, portanto, não deixe essa variável habilitada. Aconteceu o EXC_BAD_ACCESS, utilize o NSZombieEnabled, descubra onde foi o problema e desabilite, para não correr o risco de seu programa utilizar mais memória do que ele realmente necessita.

Milhares de Breakpoint

Imagine o cenário: você testou o que queria testar, utilizou centenas de breakpoints. Agora quer testar outra coisa, e quer tirar todos os breakpoints que não servem mais? Algumas pessoas não percebem, mas o Xcode permite que você os retire de maneira mais fácil. Na seção 'Groups and files', a esquerda, um dos últimos itens é o de Breakpoints. Lá você pode retirar todos os breakpoints de uma vez, basta selecionar e excluir.

Breakpoints

Enfim, por hora é só. Caso tenha alguma dúvida, ou sugestão, é só colocar nos comentários. Abraço a todos.

Ao navegar neste site, você consente o uso de cookies nossos e de terceiros, que coletam informações anônimas e são essenciais para melhorar sua experiência em nosso site.