NSLog o nome do método com Objective-C no iPhone

153

Atualmente, estamos nos definindo um mecanismo de log estendido para imprimir o nome da classe e o número da linha de origem do log.

#define NCLog(s, ...) NSLog(@"<%@:%d> %@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], \
    __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__])

Por exemplo, quando eu chamo NCLog (@ "Hello world"); A saída será:

<ApplicationDelegate:10>Hello world

Agora também quero sair do nome do método como:

<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world

Portanto, isso tornaria nossa depuração mais fácil quando podemos saber qual método está sendo chamado. Eu sei que também temos o depurador do Xcode, mas às vezes também quero fazer a depuração efetuando logout.

vodkhang
fonte
No meu último iPhoneprojeto, eu fiz isso manualmente. Adoraria ver a resposta para isso.
Jacob Relkin 5/05
Possível duplicata: stackoverflow.com/questions/969130/…
erkanyildiz

Respostas:

261
print(__FUNCTION__) // Swift
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C

Swift 3 e acima

print(#function)
desenhado
fonte
120
Você realmente deve usar NSLog(@"%@", NSStringFromSelector(_cmd)), se for usar _cmd, uma vez que o AFAIK Apple declara _cmdcomo tipo SEL, não uma string C. O fato de ser implementado como uma corda C (nas versões atuais do Mac OS X e do iPhone OS) não significa que você deva usá-lo dessa maneira, pois a Apple pode alterá-lo em uma atualização do sistema operacional.
Nick Forge
5
Sim, NSStringFromSelector é a resposta mais correta. Eu nunca uso _cmd como string c para qualquer coisa, exceto código de depuração.
drawnonward
Uau, o compilador reclama de incompatibilidade de ponteiro, mas funciona ... Então _cmd (tipo: SEL) é realmente um caractere *!?
Nicolas Miari 19/06/12
3
Chamadas de método como [self doSomething:arg1 somethingElse:arg2]get convertido na chamada de função C objc_msgSend(self, "doSomething:somethingElse:, arg1, arg2);. O segundo parâmetro de objc_msgSend()leva a char*. Lembre-se de que, como o tempo de execução do Objective-C é dinâmico, na verdade ele está usando uma tabela de pesquisa para descobrir qual método em qual classe chamar, portanto, um char * é conveniente, pois os métodos são representados como seqüências de caracteres na tabela de pesquisa.
9788 Jack
1
Para Swift 2.2 deve usarprint("\(#function)")
Jake Lin
161

Para responder tecnicamente à sua pergunta, você deseja:

NSLog(@"<%@:%@:%d>", NSStringFromClass([self class]), NSStringFromSelector(_cmd), __LINE__);

Ou você também pode fazer:

NSLog(@"%s", __PRETTY_FUNCTION__);
Dave DeLong
fonte
2
Com __FUNCTION__e seu equivalente equivalente também estão disponíveis nas funções C.
Georg Fritzsche
NB __FUNCTION__também inclui o nome da classe
OrangeDog
1
existe alguma diferença usando o NSLog (@ "% s", _func_ ); OU NSLog (@ "% s", _PRETTY_FUNCTION_ ) ???
Ravi
83

tl; dr

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

Detalhes

A Apple possui uma página de Perguntas e respostas técnicas: QA1669 - Como posso adicionar informações de contexto - como o método atual ou o número da linha - às minhas instruções de registro?

Para ajudar no log:

  • O pré-processador C fornece algumas macros .
  • Objective-C fornece expressões (métodos).
    • Passe o argumento implícito para o seletor do método atual:_cmd

Como outras respostas indicadas, para obter apenas o nome do método atual, chame:

NSStringFromSelector(_cmd)

Para obter o nome do método atual e o número da linha atual, use estas duas macros __func__e __LINE__como visto aqui:

NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);

Outro exemplo ... Trechos de código que mantenho na Biblioteca de trechos de código do Xcode:

NSLog( @"ERROR %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

… E TRACE em vez de ERRO…

NSLog( @"TRACE %@ METHOD %s:%d ", @"DescriptionGoesHere", __func__, __LINE__ );

… E uma versão mais longa usando uma descrição codificada por software passando um valor ( [rows count])…

NSLog( @"TRACE %@ METHOD %s:%d.", [NSString stringWithFormat:@"'Table of Contents.txt' file's count of Linefeed-delimited rows: %u.", [rows count]] , __func__, __LINE__ );

Macros de pré-processador para log

Observe o uso de um par de caracteres sublinhados nos dois lados da macro.

| Macro Formato | Descrição
  __func__% s Assinatura da função atual
  __LINE__% d Número da linha atual
  __FILE__% s Caminho completo para o arquivo de origem
  __PRETTY_FUNCTION__% s Como __func__, mas inclui detalhes
                                    digite informações no código C ++. 

Expressões para log

| Expressão Formato | Descrição
  NSStringFromSelector (_cmd)% @ Nome do seletor atual
  NSStringFromClass ([self class])% @ Nome da classe do objeto atual
  [[NSString% @ nome do arquivo de código-fonte
    stringWithUTF8String: __ FILE__]   
    lastPathComponent] 
  [NSThread callStackSymbols]% @ NSArray do rastreamento de pilha

Estruturas de registro

Algumas estruturas de registro também podem ajudar a obter o método atual ou o número da linha. Não tenho certeza, pois usei uma excelente estrutura de log em Java ( SLF4J + LogBack ), mas não o Cocoa.

Consulte esta pergunta para obter links para várias estruturas de registro de cacau.

Nome do Seletor

Se você tiver uma variável Seletor (um SEL ), poderá imprimir o nome do método ("mensagem") de duas maneiras, conforme descrito nesta postagem do blog do Codec :

  • Usando a chamada Objective-C para NSStringFromSelector :
    NSLog(@"%@", NSStringFromSelector(selector) );
  • Usando C direto:
    NSLog(@"%s", selector );

Essas informações foram extraídas da página de documento da Apple vinculada a partir de 19/07/2013. Essa página foi atualizada pela última vez em 10/10/2011.

Basil Bourque
fonte
1
Para C, uso sel_getName(SEL)desde SEL é um tipo opaco e pode nem sempre ser umchar *
Ethan Reesor
8
NSLog(@"%@", NSStringFromSelector(_cmd)); // Objective-C
print(__FUNCTION__) // Swift
Huynh Inc
fonte
4
Para quem se deparar com essa resposta no futuro: é equivalente à resposta aceita, mas a resposta aceita foi diferente quando foi publicada (a resposta aceita foi editada em 2014). Eu estava prestes a votação para baixo, mas depois de uma pequena investigação se votou em vez :)
FreeNickname
0

Na verdade, é tão simples quanto:

printf(_cmd);

Por alguma razão, o iOS permite que _cmd seja transmitido como um caracter literal, sem sequer um aviso de compilação. Quem sabe

Albert Renshaw
fonte
0

No Swift 4:

func test () {

print(#function)

}

test () // imprime o valor "test ()"

Ankit garg
fonte