Logs em Swift
15 Sep 2016Depois de quase 5 meses estamos de volta, 🖖.
Todo mundo, uma hora ou outra, coloca uns NSLog
s no código. Muitas vezes esse log só é útil apenas para o desenvolvimento ou debug. Então pode não ser uma boa idéia usar direto o NSLog
ou o print
do Swift
, pois esses log aparecem no console dos aparelhos.
Em Objective-C
eu tenho duas macros (que escrevi faz muitos anos) para resolver esse problema:
#ifdef DEBUG
#define DTLog(fmt, ...) NSLog((@"%s:%d %s : " fmt), __FILE__, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#else
#define DTLog NSLog
#endif
#ifdef DEBUG
#define DTLogD(fmt, ...) NSLog((@"%s:%d %s : " fmt), __FILE__, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#else
#define DTLogD(...)
#endif
Um adicional delas que eu gosto bastante é que quando o programa roda em debug, além da mensagem, são apresentados o nome do arquivo __FILE__
, a linha __LINE__
e o nome da função __PRETTY_FUNCTION__
em que elas foram chamadas. Além disso em release uma delas não mostra nada.
Note que essas são macros do pré-processador de C, isso significa que são avaliadas antes do código ser compilado e que seu comportamento depende da macro DEBUG estar definida. Quando criamos um projeto, o Xcode já define essa macro para nós:
Então se você copia-las para seu projeto tudo já vai estar funcionando!
Em Swift
as coisas mudam um pouco, não temos macros do pré-processador. Mas o equivalente direto seriam funções globais, o que não tem muito cara de Swift
. O que tenho usado1 é um struct
com duas funções estáticas:
public struct Log {
public static func info(
_ items: Any...,
functionName: String = #function,
fileName: String = #file,
lineNumber: Int = #line)
{
log(items,
functionName: functionName,
fileName: fileName,
lineNumber: lineNumber)
}
public static func debug(
_ items: Any...,
functionName: String = #function,
fileName: String = #file,
lineNumber: Int = #line)
{
#if DEBUG
log(items,
functionName: functionName,
fileName: fileName,
lineNumber: lineNumber)
#endif
}
private static func log(
_ items: [Any],
functionName: String,
fileName: String,
lineNumber: Int)
{
let url = NSURL(fileURLWithPath: fileName)
let lastPathComponent = url.lastPathComponent ?? fileName
#if DEBUG
print("[\(lastPathComponent):\(lineNumber)] \(functionName):",
separator: "",
terminator: " ")
#endif
for item in items {
print(item, separator: "", terminator: "")
}
print("")
}
}
Apesar de Swift
não ter macros, temos as Special Literal Expressions #file
, #line
e #function
que têm praticamente o mesmo comportamento. Juntando com um pouco de malabarismo com Variadic Parameters fica até mais elegante que as macros.
Mas se você copiar e colar esse código no seu projeto provavelmente ele não vai funcionar direito, isso por conta do #if DEBUG
. Isso não é uma macro, é um Conditional Compilation Blocks e o Xcode não cria automaticamente um DEBUG
para você 😔. Mas não tem problema, é só adicionar no Build Settings do projeto:
Note que diferente da macro não é atribuido um valor e a flag é precedida de -D
.
Criticas, sugestões e comentários são sempre bem-vindos, é só me pingar no @diogot ou no Slack do iOS Dev BR.
Diogo Tridapalli
@diogot
-
Já em
Swift
3.0 ↩