Pregunta ¿Hay una alternativa de Swift para NSLog (@ "% s", __PRETTY_FUNCTION__)


En Objective C puede registrar el método al que se llama utilizando:

NSLog(@"%s", __PRETTY_FUNCTION__)

Por lo general, esto se utiliza desde una macro de registro.

Aunque Swift no admite macros (creo), me gustaría utilizar una declaración de registro genérica que incluya el nombre de la función a la que se llamó. ¿Es eso posible en Swift?

Actualizar: Ahora uso esta función global para el registro que se puede encontrar aquí: https://github.com/evermeer/Stuff#print Y que puedes 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 cual dará como resultado:

️ .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

74
2018-06-25 07:21


origen


Respuestas:


Swift tiene #file, #function, #line  y #column. De Swift Lenguaje de programación:

#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.


77
2018-06-25 07:30



A partir de Swift 2.2 deberíamos usar:

  • #archivo (Cadena) El nombre del archivo en el que aparece.
  • #línea (Int) El número de línea en el que aparece.
  • #columna (Int) El número de columna en el que comienza.
  • #función (Cadena) El nombre de la declaración en la que aparece.

De 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

62
2018-03-14 15:19



Aquí está mi enfoque:

func pretty_function(file:String = __FILE__, function:String = __FUNCTION__, line:Int = __LINE__) {
    print("file:\(file.lastPathComponent) function:\(function) line:\(line)")
}

Haga de esto una función global y solo llame

pretty_function()

15
2018-03-05 17:21



A partir de XCode beta 6, puede usar reflect(self).summary para obtener el nombre de clase y __FUNCTION__ para obtener el nombre de la función, pero las cosas están un poco destrozadas, en este momento. Con suerte, encontrarán una mejor solución. Puede 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 salida como esta:

2014-08-24 09:52:12.159 SwiftLessons[1397:17145716] app: SwiftLessons class: ViewController func: flowAction

9
2017-08-24 15:51



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")
}

el resultado es algo así 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";
}

7
2017-10-28 07:28



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)")

3
2018-01-19 02:44



O 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 * /


0
2018-02-18 20:18