Есть ли быстрая альтернатива для NSLog (@"%s", довольно функция)


в Objective C вы можете зарегистрировать метод, который вызывается с помощью:

NSLog(@"%s", __PRETTY_FUNCTION__)

обычно это используется из макроса ведения журнала.

хотя Swift не поддерживает макрос (я думаю), я все же хотел бы использовать общий оператор журнала, который включает имя вызываемой функции. Возможно ли это в Swift?

обновление: Теперь я использую эту глобальную функцию для ведения журнала, который можно найти здесь: https://github.com/evermeer/Stuff#print И который вы можете установить с помощью:

pod 'Stuff/Print'

вот код:

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 "
11 75

11 ответов:

Свифт #file,#function,#line и #column. От Язык Программирования Swift:

#file - String-имя файла, в котором он появляется.

#line - Int-номер строки, на которой он появляется.

#column - Int-номер столбца, в котором он начинается.

#function - String-имя объявления, в котором оно появляется.

начиная с Swift 2.2 мы должны использовать:

  • #file (строка) имя файла, в котором он появляется.
  • # line (Int) номер строки, на которой он появляется.
  • столбец# (Int) номер столбца, в котором он начинается.
  • # function (строка) имя объявления, в котором оно появляется.

С Язык Программирования Swift (Swift 3.1) на странице 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

вот мой подход:

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

сделайте это глобальной функцией и просто вызовите

pretty_function()

начиная с Xcode beta 6, Вы можете использовать reflect(self).summary получить имя класса и __FUNCTION__ чтобы получить имя функции, но сейчас все немного искажено. Надеюсь, они найдут лучшее решение. Возможно, стоит использовать #define, пока мы не выйдем из бета-версии.

этот код:

NSLog("[%@ %@]", reflect(self).summary, __FUNCTION__)

дает такие результаты:

2014-08-24 08:46:26.606 SwiftLessons[427:16981938] [C12SwiftLessons24HelloWorldViewController (has 2 children) goodbyeActiongoodbyeAction]

EDIT: это больше кода, но приблизил меня к тому, что мне нужно, что я думаю, что вы желаемый.

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

это дает выход такой:

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

Я предпочитаю определять глобальную функцию журнала:

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

выход что-то вроде:

****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";
}

вот обновленный ответ 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)]"
}

пример использования:

LogW("Socket connection error: \(error)")

или небольшая модификация функции с помощью:

func logFunctionName(file:String = __FILE__, fnc:String = __FUNCTION__, line:(Int)=__LINE__) {
    var className = file.lastPathComponent.componentsSeparatedByString(".")
    println("\(className[0]):\(fnc):\(line)")

}

/* будет производить трассировку выполнения, как: AppDelegate: application (_: didFinishLaunchingWithOptions:): 18 Продукт: init(тип: название: год:Цена:): 34 FirstViewController: viewDidLoad (): 15 AppDelegate:applicationDidBecomeActive: 62 * /

другой способ регистрации вызова функции:

NSLog("\(self.dynamicType): %@", __FUNCTION__)

Я использую, это все, что требуется в swift-файле, все остальные файлы будут забирать его (как глобальную функцию). Когда вы хотите выпустить приложение, просто закомментируйте строку.

import UIKit

func logFunctionName(file:NSString = __FILE__, fnc:String = __FUNCTION__){  
    println("\(file.lastPathComponent):\(fnc)")
}

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

Swift 3.x+

Если вы не хотите, чтобы весь имя файла, то вот быстрое решение для этого.

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