Todo mundo, uma hora ou outra, coloca uns NSLogs no código. Muitas vezes, esse log só é útil apenas para o desenvolvimento ou debug. Então, pode não ser uma boa ideia 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ê copiá-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 usado é 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 é atribuído um valor e a flag é precedida de -D.
Críticas, sugestões e comentários são sempre bem-vindos; é só me pingar no @diogot ou no Slack do iOS Dev BR.