Preciso desabilitar o NSLog antes de lançar o aplicativo?

117

Ao lançar um aplicativo para iPhone, se eu desativar NSLog();, ele terá um desempenho melhor?

RAGOpoR
fonte
1
Em meu projeto atual, uso o UALogger . Ele não loga em produção , se você não perguntar explicitamente. E tem outros benefícios em relação ao NSLog simples, como níveis de gravidade (com DEBUG , INFO e etc.) prontos para uso. Bom trabalho!
Anton Gaenko
1
Para responder à sua pergunta sobre "terá um desempenho melhor?" Sim, é verdade, mas o rendimento que você obtém depende de quantos NSLog()você tem em seu aplicativo. NSLog()leva tempo para ser executado e adiciona sobrecarga ao tempo de execução do seu aplicativo. De qualquer forma, se ajudar no desempenho com uma macro de pré-processador DEBUG simples, devemos desabilitá-la.
Scott
Eu também sugeriria que se você tiver muitas instruções NSLog / print em seu código, isso pode sugerir que você deve passar algum tempo aprendendo mais sobre o depurador. Eu defino regularmente pontos de interrupção que imprimem informações nas quais estou interessado e continuo automaticamente. Sim, pode retardar um pouco a corrida, mas na maioria dos casos não é excessivo. Além disso, quebras condicionais para que você possa investigar quando algo inesperado aconteceu.
bshirley

Respostas:

127

Uma maneira de fazer isso é acessar as configurações de Build e, na configuração Debug, adicionar um valor ao valor "Macros de pré-processador" como:

DEBUG_MODE=1

Certifique-se de fazer isso apenas para a configuração de depuração e não para versões Beta ou de lançamento. Então, em um arquivo de cabeçalho comum, você pode fazer algo como:

#ifdef DEBUG_MODE
#define DLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DLog( s, ... ) 
#endif

Agora, em vez de NSLog usar em DLogtodos os lugares. Ao testar e depurar, você receberá mensagens de depuração. Quando você está pronto para lançar um beta ou lançamento final, todas essas DLoglinhas ficam vazias automaticamente e nada é emitido. Desta forma, não há configuração manual de variáveis ​​ou comentários de NSLogsobrigatórios. Escolher seu alvo de construção cuida disso.

Ramin
fonte
No Xcode 4.5 ele dá um aviso que diz: "A declaração implícita da função 'DLog' é inválida no C99" então isso não funciona.
Sergey Grischyov
2
@SergiusGee: Você obtém o aviso de declaração implícita se a declaração para a função não puder ser encontrada e, nesse caso, ele pensa que você está tentando declará-la. Certifique-se de que sua classe tenha acesso ao arquivo de cabeçalho onde está declarado.
sudo rm -rf
1
Não aceito o logout, pois isso impede que você receba relatórios de erro melhores dos usuários. use registro assíncrono e níveis de log para limitar o impacto de desempenho a quase zero! (ver cacau lenhador ou java's log4j
Daij-Djan
2
Eu escolheria #if em vez de #ifdef, pois DEBUG_MODE 0 ainda seguirá pelo caminho verdadeiro
Grady Player
1
isso não responde à pergunta
Martin Mlostek
117

Atualização para Xcode 5 e iOS 7

nota: para uma solução Xcode 7 / Swift 2.1 para remover as instruções print () em uma versão de lançamento, encontre minha resposta aqui .

Sim, você deve remover qualquer instrução NSLog em seu código de lançamento, pois isso apenas retarda o seu código e não tem qualquer utilidade em uma versão de lançamento. Felizmente, no Xcode 5 (iOS 7), é incrivelmente simples remover todas as suas instruções NSLog 'automaticamente' em compilações de lançamento. Então, por que não fazer?

Primeiro as 3 etapas a serem seguidas, depois alguma explicação

1) em seu projeto Xcode, localize o arquivo 'yourProjectName-prefix.pch' (normalmente você o encontrará no grupo 'arquivos de suporte', onde seu arquivo main.m está localizado

2) adicione essas 3 linhas no final do arquivo '.pch':

#ifndef DEBUG
   #define NSLog(...);
#endif

3) teste a diferença entre a sua versão de 'depuração' e 'lançamento'. Uma maneira de fazer isso é através do 'esquema de edição' -> 'executar nome do aplicativo' -> na guia 'informações', selecione usando a caixa suspensa entre depuração e lançamento. Na versão de lançamento, você não verá nenhuma saída NSLog no console de depuração!

Como tudo isso funciona?

em primeiro lugar, deve-se saber que um pré-processador é relativamente 'burro' e apenas atua como um 'substituto de texto' antes de o compilador ser chamado. Ele substitui qualquer coisa que você '#define' pelo que segue a #definedeclaração.

#define NSLog(...);

O (...)significa 'qualquer coisa' entre os colchetes (). Lembre-se também ;do final. Isso não é estritamente necessário, pois o compilador irá otimizar isso, mas eu gosto de colocá-lo lá, pois é mais 'correto'. Depois de nosso, #definenão há 'nada', então o pré-processador irá substituí-lo por 'nada', e então jogará fora a linha completa, começando em NSLog...até e incluindo o ;.

as declarações de definição podem ser tornadas condicionais usando #ifdef(se definido) ou #ifndef(se não definido)

aqui escrevemos #ifndef DEBUG, o que significa 'se o símbolo DEBUG não está definido'. O #ifdefou #ifndefprecisa ser 'fechado' com#endif

O Xcode 5 define por padrão o símbolo 'DEBUG' para nós quando o modo de construção é 'DEBUG'. Em 'release' isso não está definido. você pode verificar isso nas configurações do projeto, guia 'Configurações de compilação' -> role para baixo até a seção 'Apple LLVM 5.0 - Pré-processamento' -> macros do pré-processador. Você verá que o símbolo 'DEBUG' não está definido para versões de lançamento!

finalmente, o arquivo .pch é criado pelo Xcode automaticamente e automaticamente incluído em cada arquivo de origem durante o tempo de compilação. Portanto, é como se você tivesse colocado #definetudo em cada um de seus arquivos de origem.

Ronny Webers
fonte
1
Obrigado @Whasssaaahhh, funciona muito bem. Tenha cuidado para evitar colocar código em instruções de log! O pré-processador removerá todas as NSLoginstruções, desconsiderando o que está dentro.
Eric Platon
1
Se for um projeto mais antigo que não tem o sinalizador de depuração no pré-processador ou macros, é importante adicionar "debug = 1" para o projeto e não para o destino
Priebe
1
Além disso, não use NSLogcomo uma declaração de não fazer nada, por exemplo, em if(AllCool) NSLog(@"Cool!Do Nothing!"); else...vez disso, NSLogif(AllCool) {NSLog(@"Cool!Do Nothing!");} else...
coloque
33

Quase todas as respostas acima sugerem uma solução, mas não explicam o problema. Fiz uma pesquisa no google e descobri o motivo. Aqui está minha resposta:

Sim, se você comentar o NSLog em sua versão de lançamento, o desempenho será melhor. Porque NSLog é muito lento. Por quê? NSLog fará duas coisas 1) escrever mensagens de log no Apple System Logging (ASL), 2) se o aplicativo for executado em xcode, ele gravará em stderr também.

O principal problema está no primeiro. Para obter um thread seguro, cada vez que o NSLog é chamado, ele abre uma conexão com o recurso ASL , envia uma mensagem e fecha a conexão. A operação de conexão é muito cara. Outro motivo é que o NSLog gasta algum tempo para obter o registro de data e hora.

Referência aqui .

Andrew
fonte
23

Meu favorito pessoal é usar uma macro variável.

#ifdef NDEBUG
    #define NSLog(...) /* suppress NSLog when in release mode */
#endif
Eytan
fonte
1
Onde você coloca isso?
user6631314
20

Além de todas as pessoas que sabiamente comentaram que não ligar NSLog()na produção é um pouco mais rápido, vou acrescentar que:

Todas essas NSLog()strings de saída são visíveis para qualquer pessoa que baixe seu aplicativo da loja e o execute com o dispositivo conectado a um mac executando o Xcode (por meio da janela do Organizer).

Dependendo das informações que você registra (e especialmente se seu aplicativo contata um servidor, faz autenticação, etc.), isso pode ser um sério problema de segurança .

Nicolas Miari
fonte
obrigado pela informação - isto está em algum lugar do documento, ou você acabou de descobrir isso sozinho? Isso ainda é válido para impressão em Swift?
Ronny Webers
Não me lembro de ter lido nenhuma documentação. Acabei de instalar minha compilação arquivada (mesmo binário que enviei para a loja) no meu dispositivo e conectei-o ao Xcode. Não tenho ideia se é o mesmo para o de Swift print(), mas provavelmente é.
Nicolas Miari
@NicolasMiari O que você quer dizer com conectado ao Xcode? Como podemos conectar nosso binário ao Xcode, na verdade eu quero tentar o mesmo. Então, por favor, sugira. Obrigado.
iDevAmit
@iDeveloper Quero dizer, baixe seu aplicativo da AppStore para um dispositivo (por exemplo, um iPhone), conecte esse dispositivo ao Xcode via USB, inicie seu aplicativo e observe os logs na janela "Dispositivos" do Xcode.
Nicolas Miari
3
@Whasssaaahhh print não sai no console do dispositivo ... acabei de testar isso
Anish Parajuli 웃
13

Configuração padrão do projeto

Dentro da configuração padrão atual do projeto no Xcode, a NS_BLOCK_ASSERTIONSmacro será definida como 1 na versão de lançamento e DEBUG=1na versão de depuração.

Portanto, prefiro o método a seguir.

// NS_BLOCK_ASSERTIONS is defined by default, as shown in the screenshot above.
// Or, you can define yourself Flags in the `Other C Flags` -> `Release`.
#ifndef NS_BLOCK_ASSERTIONS
    #define _DEBUG
#endif

#ifdef _DEBUG
// for debug mode 
#define DLog(fmt,...) NSLog(@"%s " fmt, __FUNCTION, ##__VA_ARGS__) 
... /// something extra
#else
// for release mode
#define DLog(fmt,...) /* throw it away */
... /// something extra
#endif
AechoLiu
fonte
5

Sim, você deve desativá-lo. Especialmente se você estiver tentando maximizar a velocidade do seu código. O NSLogging da esquerda e da direita polui o log do sistema que outros desenvolvedores podem estar tentando vasculhar e pode ter um grande impacto no código crítico de velocidade (dentro de loops, etc.) Eu deixei acidentalmente algumas mensagens de log em uma função recursiva uma vez e conseguiu lançar uma atualização com um "aumento de velocidade de 30%!" algumas semanas depois ... ;-)

Ben Gotow
fonte
5

Todas boas respostas, mas aqui está outro pequeno truque que você pode considerar usar, principalmente nas fases de desenvolvimento / teste do seu aplicativo.

Também pode ser útil para o código de lançamento do aplicativo, se você quiser apenas desligar SEU código de depuração, e não mensagens que podem indicar problemas fora do controle direto do seu código.

O truque:

Você pode desativar o NSLog por arquivo .m simplesmente incluindo a linha a seguir na parte superior do arquivo .m :

#define NSLog(...)

( NOTA: NÃO coloque este arquivo .h, apenas o arquivo .m! )

Isso apenas faz com que o compilador avalie NSLog()expandindo a macro do pré-processador. A macro não faz nada além de remover os argumentos.

se quiser ligá-lo novamente, você sempre pode usar

#undef NSLog

Você poderia, por exemplo, apenas evitar chamadas para NSLog em torno de um determinado grupo de métodos fazendo algo como

#define NSLog(...)
-(void) myProblematicMethodThatSometimesNeedsDebugging {
    ...
}
#undef NSLog
não sincronizado
fonte
3

NSLog é lento e não deve ser usado para compilações de lançamento. Uma macro simples como a abaixo irá desativá-la junto com quaisquer declarações que você possa ter que também devem ser desativadas. No caso menos comum em que você deseja NSLog em uma versão de lançamento, basta chamá-lo diretamente. Não se esqueça de adicionar "-DNDEBUG" às configurações de compilação de "outras sinalizações c".

#ifdef NDEBUG
#define MYLog(f, ...) 
#else
#define MYLog(f, ...) NSLog(f, ## __VA_ARGS__)
#endif
papahabla
fonte
2

no arquivo pch anote isso antes de #endif

#define NSLog() //
Sandeep Saurabh
fonte
0

que tal isso?

#ifndef DEBUG_MODE
        fclose(stderr);     // the simplest way to disable output from NSLog
#endif    
roberto.buratti
fonte
1
isto desativa a saída, mas não economiza tempo de processamento, ou seja, NSLog ainda é chamado e seus argumentos analisados
dwery
0
var showDebugLogs = false;

    func DLog(format: String, args: CVarArgType...) {
        if showDebugLogs{
        println(String(format: format, arguments: args))
        }
    }

Isso aceitará os argumentos adicionais também .. Apenas o valor do parâmetro showDebugLogs para true ou false, conforme sua necessidade

Zahur
fonte
Isso é bom, mas ainda tem o problema de toda a sobrecarga de chamada e de qualquer sobrecarga (e efeitos colaterais potenciais) de computar quaisquer argumentos passados ​​para a Dlogfunção.
Todd Lehman