使用swift记录方法签名

时间:2014-06-04 22:07:55

标签: ios cmd swift ios8

我正在尝试重写我的日志类,我想知道如何在swift文件中替换 PRETTY_FUNCTION 或NSStringFromSelector(_cmd)以跟踪方法调用?

15 个答案:

答案 0 :(得分:86)

swift中的特殊文字如下(来自[swift guide]

#file 字符串它出现的文件的名称。

#line Int 出现的行号。

#column Int 它开始的列号。

#function 字符串它出现的声明的名称。


在Swift 2.2b4之前,这些是

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html)):

__FILE__ 字符串它出现的文件的名称。

__LINE__ Int 出现的行号。

__COLUMN__ Int 它开始的列号。

__FUNCTION__ 字符串它出现的声明的名称。

您可以在记录语句中使用它们,如下所示:

println("error occurred on line \(__LINE__) in function \(__FUNCTION__)")

答案 1 :(得分:57)

查看我刚刚发布的新图书馆:https://github.com/DaveWoodCom/XCGLogger

它是Swift的调试日志库。

能够使用#function宏的关键是将它们设置为日志记录功能的默认值。然后,编译器将使用期望值填充它们。

func log(logMessage: String, functionName: String = #function) {
    print("\(functionName): \(logMessage)")
}

然后打电话:

log("my message")

它按预期工作,给你类似的东西:

whateverFunction(): my message

有关其工作原理的更多信息:https://www.cerebralgardens.com/blog/entry/2014/06/09/the-first-essential-swift-3rd-party-library-to-include-in-your-project

答案 2 :(得分:9)

我会用这样的东西:

func Log(message: String = "", _ path: String = __FILE__, _ function: String = __FUNCTION__) {
    let file = path.componentsSeparatedByString("/").last!.componentsSeparatedByString(".").first! // Sorry
    NSLog("\(file).\(function): \(message)")
}

与之前答案相比的改进:

  • 使用NSLog,而不是print / println
  • 不使用在字符串上不可用的lastPathComponent
  • 日志消息是可选的

答案 3 :(得分:5)

试试这个:

class Log {
    class func msg(message: String,
        functionName:  String = __FUNCTION__, fileNameWithPath: String = __FILE__, lineNumber: Int = __LINE__ ) {
        // In the default arguments to this function:
        // 1) If I use a String type, the macros (e.g., __LINE__) don't expand at run time.
        //  "\(__FUNCTION__)\(__FILE__)\(__LINE__)"
        // 2) A tuple type, like,
        // typealias SMLogFuncDetails = (String, String, Int)
        //  SMLogFuncDetails = (__FUNCTION__, __FILE__, __LINE__) 
        //  doesn't work either.
        // 3) This String = __FUNCTION__ + __FILE__
        //  also doesn't work.

        var fileNameWithoutPath = fileNameWithPath.lastPathComponent

#if DEBUG
        let output = "\(NSDate()): \(message) [\(functionName) in \(fileNameWithoutPath), line \(lineNumber)]"
        println(output)
#endif
    }
}

使用日志记录:

let x = 100
Log.msg("My output message \(x)")

答案 4 :(得分:5)

以下是我使用的内容:https://github.com/goktugyil/QorumLogs
它就像XCGLogger但更好。

func myLog<T>(object: T, _ file: String = __FILE__, _ function: String = __FUNCTION__, _ line: Int = __LINE__) {
    let info = "\(file).\(function)[\(line)]:\(object)"
    print(info)
}

答案 5 :(得分:4)

对于Swift 3及以上版本:

print("\(#function)")

答案 6 :(得分:3)

这将仅在调试模式下打印:

func debugLog(text: String,  fileName: String = __FILE__, function: String =  __FUNCTION__, line: Int = __LINE__) {
    debugPrint("[\((fileName as NSString).lastPathComponent), in \(function)() at line: \(line)]: \(text)")
}

结果:

"[Book.swift, in addPage() at line: 33]: Page added with success"

答案 7 :(得分:2)

这将一次性获取类和函数名称:

var name = NSStringFromClass(self.classForCoder) + "." + __FUNCTION__

答案 8 :(得分:1)

Swift 3支持带日期,函数名,文件名,行号的debugLog对象:

- (void)applicationWillTerminate:(UIApplication *)application {
        if ([languageSelected isEqualToString:@"en_US"]) {
            LocalizationSetLanguage(@"en");
            NSArray* languages = [NSArray arrayWithObjects:@"en", nil];
            [[NSUserDefaults standardUserDefaults] setObject:languages forKey:@"AppleLanguages"];
            [[NSUserDefaults standardUserDefaults] synchronize];
            [[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceLeftToRight];
        } else if ([languageSelected isEqualToString:@"ar"]) {
            LocalizationSetLanguage(@"ar");
            NSArray* languages = [NSArray arrayWithObjects:@"ar", nil];
            [[NSUserDefaults standardUserDefaults] setObject:languages forKey:@"AppleLanguages"];
            [[NSUserDefaults standardUserDefaults] synchronize];
            [[UIView appearance] setSemanticContentAttribute:UISemanticContentAttributeForceRightToLeft];
        }
}

答案 9 :(得分:1)

这似乎在swift 3.1中运行良好

print("File: \((#file as NSString).lastPathComponent) Func: \(#function) Line: \(#line)")

答案 10 :(得分:1)

这是我对它的看法。

func Log<T>(_ object: Shit, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {

var filename = (file as NSString).lastPathComponent
filename = filename.components(separatedBy: ".")[0]

let currentDate = Date()
let df = DateFormatter()
df.dateFormat = "HH:mm:ss.SSS"

print("┌──────────────┬───────────────────────────────────────────────────────────────")
print("│ \(df.string(from: currentDate)) │ \(filename).\(function) (\(line))")
print("└──────────────┴───────────────────────────────────────────────────────────────")
print("  \(object)\n")}

希望你喜欢。

enter image description here

答案 11 :(得分:1)

Swift 4,基于所有这些出色的答案。 ❤️

/*
 That's how I protect my virginity.
*/

import Foundation

/// Based on [this SO question](https://stackoverflow.com/questions/24048430/logging-method-signature-using-swift).
class Logger {

    // MARK: - Lifecycle

    private init() {} // Disallows direct instantiation e.g.: "Logger()"

    // MARK: - Logging

    class func log(_ message: Any = "",
                   withEmoji: Bool = true,
                   filename: String = #file,
                   function: String =  #function,
                   line: Int = #line) {

        if withEmoji {
            let body = emojiBody(filename: filename, function: function, line: line)
            emojiLog(messageHeader: emojiHeader(), messageBody: body)

        } else {
            let body = regularBody(filename: filename, function: function, line: line)
            regularLog(messageHeader: regularHeader(), messageBody: body)
        }

        let messageString = String(describing: message)
        guard !messageString.isEmpty else { return }
        print(" └  \(messageString)\n")
    }
}

// MARK: - Private

// MARK: Emoji

private extension Logger {

    class func emojiHeader() -> String {
        return "⏱ \(formattedDate())"
    }

    class func emojiBody(filename: String, function: String, line: Int) -> String {
        return " \(filenameWithoutPath(filename: filename)), in  \(function) at #️⃣ \(line)"
    }

    class func emojiLog(messageHeader: String, messageBody: String) {
        print("\(messageHeader) │ \(messageBody)")
    }
}

// MARK: Regular

private extension Logger {

    class func regularHeader() -> String {
        return " \(formattedDate()) "
    }

    class func regularBody(filename: String, function: String, line: Int) -> String {
        return " \(filenameWithoutPath(filename: filename)), in \(function) at \(line) "
    }

    class func regularLog(messageHeader: String, messageBody: String) {
        let headerHorizontalLine = horizontalLine(for: messageHeader)
        let bodyHorizontalLine = horizontalLine(for: messageBody)

        print("┌\(headerHorizontalLine)┬\(bodyHorizontalLine)┐")
        print("│\(messageHeader)│\(messageBody)│")
        print("└\(headerHorizontalLine)┴\(bodyHorizontalLine)┘")
    }

    /// Returns a `String` composed by horizontal box-drawing characters (─) based on the given message length.
    ///
    /// For example:
    ///
    ///     " ViewController.swift, in viewDidLoad() at 26 " // Message
    ///     "──────────────────────────────────────────────" // Returned String
    ///
    /// Reference: [U+250x Unicode](https://en.wikipedia.org/wiki/Box-drawing_character)
    class func horizontalLine(for message: String) -> String {
        return Array(repeating: "─", count: message.count).joined()
    }
}

// MARK: Util

private extension Logger {

    /// "/Users/blablabla/Class.swift" becomes "Class.swift"
    class func filenameWithoutPath(filename: String) -> String {
        return URL(fileURLWithPath: filename).lastPathComponent
    }

    /// E.g. `15:25:04.749`
    class func formattedDate() -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "HH:mm:ss.SSS"
        return "\(dateFormatter.string(from: Date()))"
    }
}

  

使用Logger.log()进行呼叫-(默认情况下,表情符号处于启用状态):

emojiLog


  

使用Logger.log(withEmoji: false)进行呼叫:

regularLog


  

更多用法示例:

Logger.log()
Logger.log(withEmoji: false)
Logger.log("I'm a virgin.")
Logger.log("I'm a virgin.", withEmoji: false)
Logger.log(NSScreen.min.frame.maxX) // Can handle "Any" (not only String).

答案 12 :(得分:0)

我发布了一个新图书馆:Printer

它有许多功能可以让您以不同的方式登录。

要记录成功消息:

Printer.log.success(details: "This is a Success message.")

<强>输出:

Printer ➞ [✅ Success] [⌚04-27-2017 10:53:28] ➞ ✹✹This is a Success message.✹✹
[Trace] ➞ ViewController.swift ➞ viewDidLoad() #58

免责声明:此库已由我创建。

答案 13 :(得分:0)

func Log<T>(_ object: T, fileName: String = #file, function: String =  #function, line: Int = #line) {
    NSLog("\((fileName as NSString).lastPathComponent), in \(function) at line: \(line): \(object)")
}

答案 14 :(得分:0)

使用os_log的替代版本可能是:

func Log(_ msg: String = "", _ file: NSString = #file, _ function: String = #function) {
    let baseName = file.lastPathComponent.replacingOccurrences(of: ".swift", with: "")
    os_log("%{public}@:%{public}@: %@", type: .default, baseName, function, msg)
}

在字符串处理上仍然很繁琐,如果您负担不起,请直接使用os_log。