NSLog için bir Swift alternatifi var mı (@ “% s”, __PRETTY_FUNCTION__)


88

Hedef C'de, çağrılan yöntemi aşağıdakileri kullanarak günlüğe kaydedebilirsiniz:

NSLog(@"%s", __PRETTY_FUNCTION__)

Bu genellikle bir günlük makrosundan kullanılır.

Swift, makroyu desteklemese de (sanırım) yine de çağrılan işlevin adını içeren genel bir günlük ifadesi kullanmak istiyorum. Swift'de bu mümkün mü?

Güncelleme: Şimdi, şu adreste bulabileceğiniz günlük kaydı için bu genel işlevi kullanıyorum: https://github.com/evermeer/Stuff#print Ve bunları kullanarak yükleyebilirsiniz:

pod 'Stuff/Print'

İşte kod:

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

Bunun gibi kullanabileceğiniz:

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)    

Hangi sonuçlanır:

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

1
Ben kullanıyorumNSLog("Running %@ : %@",NSStringFromClass(self.dynamicType),__FUNCTION__)
Magster


1
Sanırım kayıt stiliniz "güzel işlev" in tanımı olmalı. Paylaşım için teşekkürler.
HuaTham

Yanıtlar:


101

Swift vardır #file, #function, #line ve #column. Gönderen Swift Programlama Dili :

#file - Dize - İçinde göründüğü dosyanın adı.

#line - Int - Göründüğü satır numarası.

#column - Int - Başladığı sütun numarası.

#function - Dize - İçinde göründüğü bildirimin adı.


11
Elbette - hepsi C'den geliyor. Ancak bu __PRETTY_FUNCTION__, verilen seçeneklerden kolayca yaratılamayan hakkındaki soruyu yanıtlamadı . (Var mı __CLASS__? Eğer öyleyse, bu yardımcı olur.)
Olie

10
Swift 2.2'de #function, #file ve diğerlerini burada gösterildiği gibi kullanmalısınız: stackoverflow.com/a/35991392/1151916
Ramis

70

Swift 2.2'den başlayarak şunları kullanmalıyız:

  • #file (Dize) İçinde göründüğü dosyanın adı.
  • #line (Int) Göründüğü satır numarası.
  • #column (Int) Başladığı sütun numarası.
  • #function (Dize) İçinde göründüğü bildirimin adı.

Gönderen Swift Programlama Dili (Swift 3.1) sayfa 894 de.

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

1
Bu, şu anda doğru cevap olarak işaretlenmelidir.
Danny Bravo

18

Swift 4
İşte benim yaklaşımım:

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

Bunu küresel bir işlev yapın ve sadece arayın

pretty_function()

Bonus: İş parçacığının bir arka plan iş parçacığı için [T] ve Ana ileti dizisi için [M] üzerinde yürütüldüğünü göreceksiniz.


Dosyanın bildirimini String'den NSString'e değiştirmeniz gerekiyor. lastPathComponent, String üzerinde kullanılamaz.
primulaveris

1
Müthiş dostum. Swift> 2.1 için küçük değişiklik: "println", "yazdır" olarak yeniden adlandırıldı. print ("dosya: (file.debugDescription) işlev: (işlev) satır: (satır)")
John Doe

Harika, işe yaraması güzel. Sınıf / nesneyi bir şekilde ona geçirebilmek harika olurdu (bir seçenek, açık bir öz argüman kullanmaktır). Teşekkürler.
Tibet Deniz Kıyısı

Yaklaşımınızla ilgili sorunlar: - Bu işlev iş parçacığı için güvenli değildir. Aynı anda farklı konulardan çağırırsanız, bazı kötü sürprizlere hazırlıklı olun - Genel işlevleri kullanmak kötü bir uygulamadır
Karoly Nyisztor

9

XCode beta 6'dan itibaren, reflect(self).summarysınıf adını ve __FUNCTION__işlev adını almak için kullanabilirsiniz, ancak şu anda işler biraz karışık. Umarım daha iyi bir çözüm bulurlar. Beta sürümünden çıkana kadar bir #define kullanmak faydalı olabilir.

Bu kod:

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

bunun gibi sonuçlar verir:

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

DÜZENLEME: Bu daha çok kod, ama beni ihtiyacım olan şeye yaklaştırdı, ki bence istediğin buydu.

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

Şu şekilde çıktı verir:

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

8

Genel bir günlük işlevi tanımlamayı tercih ederim:

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

çıktı şuna benzer:

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

Aslında burada genel bir işleve ihtiyacınız yok, çünkü objectparametre Anyyerine olarak bildirilebilir T.
38'de werediver

5

İşte güncellenmiş bir Swift 2 cevabı.

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

Kullanım örneği:

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

1
Bu harika. Ama sonra tekrar .. LogW, print () ile tamamen aynı şekilde kullanılamaz (parametrelerle, virgülle ayrılmış) ..
Guntis Treulands

"LogW, print () ile tam olarak aynı şekilde kullanılamaz (parametrelerle, virgülle ayrılmış" Bu desteği eklemeyi düşünüyordum ama ihtiyacım olmadığını fark ettim. "LogW (" Soket bağlantı hatası: (hata) diğer bilgiler : (otherInfo) ")"
Daniel Ryan

1
Doğru. Pekala, etrafı düzelttim ve bulduğum tek başka çözüm de - ifadeyi tutmak için extra () kullanmaktı, mümkün olduğunca print () 'e benzer hale getirmek için. Cevabınızı bunu oluşturmak için kullandınız github.com/GuntisTreulands/ColorLogger-Swift Neyse, çok teşekkürler! :)
Guntis Treulands

Çok kullanışlı! Swift 2.2 itibariyle,__FUNCTION__ becomes #function, __FILE__ becomes #file, and __LINE__ becomes #line.
Carl Smith

Yeni değerlerle sorun yaşadık. Kod tabanımızı güncelleyene kadar 3. sürüme kadar bekleyeceğiz.
Daniel Ryan

0

Veya aşağıdakilerle hafif işlev değişikliği:

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

}

/ * aşağıdaki gibi bir yürütme izi üretecektir: AppDelegate: application (_: didFinishLaunchingWithOptions :): 18 Product: init (type: name: year: price :): 34 FirstViewController: viewDidLoad (): 15 AppDelegate: applicationDidBecomeActive: 62 * /


0

Ben kullanıyorum, hızlı bir dosyada gerekli olan tek şey bu, diğer tüm dosyalar onu alacak (genel bir işlev olarak). Uygulamayı serbest bırakmak istediğinizde, sadece satırı yorumlayın.

import UIKit

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

0

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

0

Swift 3.x +

Tüm dosya adını istemiyorsanız, işte bunun için hızlı bir düzeltme.

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

0

İşlev çağrısını kaydetmenin başka bir yolu:

NSLog("\(type(of:self)): %@", #function)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.