En Objective C puede registrar el método que se está llamando usando:
NSLog(@"%s", __PRETTY_FUNCTION__)
Por lo general, esto se usa desde una macro de registro.
Aunque Swift no es compatible con macros (creo), todavía me gustaría usar una declaración de registro genérica que incluya el nombre de la función que se llamó. ¿Es eso posible en Swift?
Actualización: ahora uso esta función global para el registro que se puede encontrar aquí: https://github.com/evermeer/Stuff#print Y que puede instalar usando:
pod 'Stuff/Print'
Aquí está el código:
public class Stuff {
public enum logLevel: Int {
case info = 1
case debug = 2
case warn = 3
case error = 4
case fatal = 5
case none = 6
public func description() -> String {
switch self {
case .info:
return "❓"
case .debug:
return "✳️"
case .warn:
return "⚠️"
case .error:
return "🚫"
case .fatal:
return "🆘"
case .none:
return ""
}
}
}
public static var minimumLogLevel: logLevel = .info
public static func print<T>(_ object: T, _ level: logLevel = .debug, filename: String = #file, line: Int = #line, funcname: String = #function) {
if level.rawValue >= Stuff.minimumLogLevel.rawValue {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy HH:mm:ss:SSS"
let process = ProcessInfo.processInfo
let threadId = "?"
let file = URL(string: filename)?.lastPathComponent ?? ""
Swift.print("\n\(level.description()) .\(level) ⏱ \(dateFormatter.string(from: Foundation.Date())) 📱 \(process.processName) [\(process.processIdentifier):\(threadId)] 📂 \(file)(\(line)) ⚙️ \(funcname) ➡️\r\t\(object)")
}
}
}
Que puedes usar así:
Stuff.print("Just as the standard print but now with detailed information")
Stuff.print("Now it's a warning", .warn)
Stuff.print("Or even an error", .error)
Stuff.minimumLogLevel = .error
Stuff.print("Now you won't see normal log output")
Stuff.print("Only errors are shown", .error)
Stuff.minimumLogLevel = .none
Stuff.print("Or if it's disabled you won't see any log", .error)
Lo que resultará en:
✳️ .debug ⏱ 02/13/2017 09:52:51:852 📱 xctest [18960:?] 📂 PrintStuffTests.swift(15) ⚙️ testExample() ➡️
Just as the standard print but now with detailed information
⚠️ .warn ⏱ 02/13/2017 09:52:51:855 📱 xctest [18960:?] 📂 PrintStuffTests.swift(16) ⚙️ testExample() ➡️
Now it's a warning
🚫 .error ⏱ 02/13/2017 09:52:51:855 📱 xctest [18960:?] 📂 PrintStuffTests.swift(17) ⚙️ testExample() ➡️
Or even an error
🚫 .error ⏱ 02/13/2017 09:52:51:855 📱 xctest [18960:?] 📂 PrintStuffTests.swift(21) ⚙️ testExample() ➡️
Only errors are shown
NSLog("Running %@ : %@",NSStringFromClass(self.dynamicType),__FUNCTION__)
Respuestas:
Swift tiene
#file
,#function
,#line
y#column
. Desde Swift Programming Language :#file
- Cadena: el nombre del archivo en el que aparece.#line
- Int: el número de línea en el que aparece.#column
- Int: el número de columna en el que comienza.#function
- Cadena: el nombre de la declaración en la que aparece.fuente
__PRETTY_FUNCTION__
, que no se crea fácilmente a partir de las opciones dadas. (¿Hay un__CLASS__
? Si es así, eso ayudaría.)A partir de Swift 2.2 deberíamos usar:
Desde El lenguaje de programación Swift (Swift 3.1) en la página 894.
func specialLiterals() { print("#file literal from file: \(#file)") print("#function literal from function: \(#function)") print("#line: \(#line) -> #column: \(#column)") } // Output: // #file literal from file: My.playground // #function literal from function: specialLiterals() // #line: 10 -> #column: 42
fuente
Swift 4
Este es mi enfoque:
func pretty_function(_ file: String = #file, function: String = #function, line: Int = #line) { let fileString: NSString = NSString(string: file) if Thread.isMainThread { print("file:\(fileString.lastPathComponent) function:\(function) line:\(line) [M]") } else { print("file:\(fileString.lastPathComponent) function:\(function) line:\(line) [T]") } }
Haga de esto una función global y simplemente llame
Bono: Verá que el hilo se ejecuta en, [T] para un hilo de fondo y [M] para el hilo principal.
fuente
A partir de XCode beta 6, puede usar
reflect(self).summary
para obtener el nombre de la clase y el nombre__FUNCTION__
de la función, pero las cosas están un poco destrozadas, en este momento. Con suerte, encontrarán una mejor solución. Podría valer la pena usar un #define hasta que salgamos de la versión beta.Este código:
NSLog("[%@ %@]", reflect(self).summary, __FUNCTION__)
da resultados como este:
2014-08-24 08:46:26.606 SwiftLessons[427:16981938] [C12SwiftLessons24HelloWorldViewController (has 2 children) goodbyeActiongoodbyeAction]
EDITAR: Esto es más código, pero me acercó más a lo que necesitaba, que creo que es lo que querías.
func intFromString(str: String) -> Int { var result = 0; for chr in str.unicodeScalars { if (chr.isDigit()) { let value = chr - "0"; result *= 10; result += value; } else { break; } } return result; } @IBAction func flowAction(AnyObject) { let cname = _stdlib_getTypeName(self) var parse = cname.substringFromIndex(1) // strip off the "C" var count = self.intFromString(parse) var countStr = String(format: "%d", count) // get the number at the beginning parse = parse.substringFromIndex(countStr.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let appName = parse.substringToIndex(count) // pull the app name parse = parse.substringFromIndex(count); // now get the class name count = self.intFromString(parse) countStr = String(format: "%d", count) parse = parse.substringFromIndex(countStr.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) let className = parse.substringToIndex(count) NSLog("app: %@ class: %@ func: %@", appName, className, __FUNCTION__) }
Da una salida como esta:
2014-08-24 09:52:12.159 SwiftLessons[1397:17145716] app: SwiftLessons class: ViewController func: flowAction
fuente
Prefiero definir una función de registro global:
[Swift 3.1]
func ZYLog(_ object: Any?, filename: String = #file, line: Int = #line, funcname: String = #function) { #if DEBUG print("****\(Date()) \(filename)(\(line)) \(funcname):\r\(object ?? "nil")\n") #endif }
[Swift 3.0]
func ZYLog<T>(_ object: T?, filename: String = #file, line: Int = #line, funcname: String = #function) { #if DEBUG print("****\(Date()) \(filename)(\(line)) \(funcname):\r\(object)\n") #endif }
[Swift 2.0]
func ZYLog<T>(object: T, filename: String = __FILE__, line: Int = __LINE__, funcname: String = __FUNCTION__) { println("****\(filename.lastPathComponent)(\(line)) \(funcname):\r\(object)\n") }
la salida es algo como:
****ZYHttpSessionManager.swift(78) POST(_:parameters:success:failure:): [POST] user/login, { "auth_key" = xxx; "auth_type" = 0; pwd = xxx; user = "xxx"; } ****PointViewController.swift(162) loadData(): review/list [limit: 30, skip: 0] ****ZYHttpSessionManager.swift(66) GET(_:parameters:success:failure:): [GET] review/list, { "auth_key" = xxx; uuid = "xxx"; }
fuente
object
parámetro se puede declarar como enAny
lugar deT
.Aquí hay una respuesta actualizada de Swift 2.
func LogW(msg:String, function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__){ print("[WARNING]\(makeTag(function, file: file, line: line)) : \(msg)") } private func makeTag(function: String, file: String, line: Int) -> String{ let url = NSURL(fileURLWithPath: file) let className:String! = url.lastPathComponent == nil ? file: url.lastPathComponent! return "\(className) \(function)[\(line)]" }
Ejemplo de uso:
LogW("Socket connection error: \(error)")
fuente
__FUNCTION__ becomes #function, __FILE__ becomes #file, and __LINE__ becomes #line.
O una ligera modificación de la función con:
func logFunctionName(file:String = __FILE__, fnc:String = __FUNCTION__, line:(Int)=__LINE__) { var className = file.lastPathComponent.componentsSeparatedByString(".") println("\(className[0]):\(fnc):\(line)")
}
/ * producirá un seguimiento de ejecución como: AppDelegate: application (_: didFinishLaunchingWithOptions :): 18 Producto: init (tipo: nombre: año: precio :): 34 FirstViewController: viewDidLoad (): 15 AppDelegate: applicationDidBecomeActive: 62 * /
fuente
Yo uso, esto es todo lo que se requiere en un archivo rápido, todos los demás archivos lo recogerán (como una función global). Cuando desee lanzar la aplicación, simplemente comente la línea.
import UIKit func logFunctionName(file:NSString = __FILE__, fnc:String = __FUNCTION__){ println("\(file.lastPathComponent):\(fnc)") }
fuente
Swift 3.0
public func LogFunction<T>(object: T, filename: String = #file, line: Int = #line, funcname: String = #function) { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "MM/dd/yyyy HH:mm:ss:SSS" let process = ProcessInfo.processInfo() let threadId = "?" print("\(dateFormatter.string(from:Date())) \(process.processName) [\(process.processIdentifier):\(threadId)] \(filename)(\(line)) \(funcname)::: \(object)") }
fuente
Swift 3.x +
Si no desea el nombre completo del archivo, aquí tiene una solución rápida.
func trace(fileName:String = #file, lineNumber:Int = #line, functionName:String = #function) -> Void { print("filename: \(fileName.components(separatedBy: "/").last!) function: \(functionName) line: #\(lineNumber)") } filename: ViewController.swift function: viewDidLoad() line: #42
fuente
Otra forma de registrar la llamada a la función:
NSLog("\(type(of:self)): %@", #function)
fuente