W Objective C możesz zarejestrować wywoływaną metodę za pomocą:
NSLog(@"%s", __PRETTY_FUNCTION__)
Zwykle jest to używane z makra rejestrującego.
Chociaż Swift nie obsługuje makr (wydaje mi się), nadal chciałbym użyć ogólnej instrukcji dziennika, która zawiera nazwę funkcji, która została wywołana. Czy to możliwe w Swift?
Aktualizacja: Teraz używam tej globalnej funkcji do logowania, którą można znaleźć tutaj: https://github.com/evermeer/Stuff#print I którą możesz zainstalować za pomocą:
pod 'Stuff/Print'
Oto 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)")
}
}
}
Którego możesz użyć w ten sposób:
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)
Co spowoduje:
✳️ .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__)
Odpowiedzi:
Swift ma
#file
,#function
,#line
i#column
. Z języka szybkiego programowania :#file
- String - nazwa pliku, w którym się pojawia.#line
- Int - numer wiersza, w którym się pojawia.#column
- Int - numer kolumny, w której się zaczyna.#function
- String - nazwa deklaracji, w której występuje.źródło
__PRETTY_FUNCTION__
, co nie jest łatwe do stworzenia z podanych opcji. (Czy istnieje__CLASS__
? Jeśli tak, to by pomogło.)Począwszy od Swift 2.2 powinniśmy użyć:
Z języka programowania Swift (Swift 3.1) na stronie 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
źródło
Swift 4
Oto moje podejście:
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]") } }
Ustaw tę funkcję jako globalną i po prostu wywołaj
Bonus: Zobaczysz, że wątek jest wykonywany, [T] dla wątku w tle i [M] dla wątku głównego.
źródło
Począwszy od XCode beta 6, możesz użyć
reflect(self).summary
do uzyskania nazwy klasy i__FUNCTION__
nazwy funkcji, ale w tej chwili sytuacja jest nieco zniekształcona. Miejmy nadzieję, że znajdą lepsze rozwiązanie. Warto użyć #define, dopóki nie wyjdziemy z wersji beta.Ten kod:
NSLog("[%@ %@]", reflect(self).summary, __FUNCTION__)
daje takie wyniki:
2014-08-24 08:46:26.606 SwiftLessons[427:16981938] [C12SwiftLessons24HelloWorldViewController (has 2 children) goodbyeActiongoodbyeAction]
EDYCJA: To jest więcej kodu, ale zbliżyło mnie do tego, czego potrzebowałem, a myślę, że właśnie tego chciałeś.
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__) }
Daje takie wyjście:
2014-08-24 09:52:12.159 SwiftLessons[1397:17145716] app: SwiftLessons class: ViewController func: flowAction
źródło
Wolę zdefiniować funkcję dziennika globalnego:
[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") }
wynik jest podobny do:
****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"; }
źródło
object
parametr można zadeklarować jakoAny
zamiastT
.Oto zaktualizowana odpowiedź 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)]" }
Przykład użycia:
LogW("Socket connection error: \(error)")
źródło
__FUNCTION__ becomes #function, __FILE__ becomes #file, and __LINE__ becomes #line.
Lub niewielka modyfikacja funkcji za pomocą:
func logFunctionName(file:String = __FILE__, fnc:String = __FUNCTION__, line:(Int)=__LINE__) { var className = file.lastPathComponent.componentsSeparatedByString(".") println("\(className[0]):\(fnc):\(line)")
}
/ * wygeneruje ślad wykonania, taki jak: AppDelegate: application (_: didFinishLaunchingWithOptions :): 18 Product: init (typ: nazwa: rok: cena :): 34 FirstViewController: viewDidLoad (): 15 AppDelegate: applicationDidBecomeActive: 62 * /
źródło
Używam, to wszystko, co jest wymagane w pliku swift, wszystkie inne pliki będą go odbierać (jako funkcja globalna). Jeśli chcesz zwolnić aplikację, po prostu zakomentuj linię.
import UIKit func logFunctionName(file:NSString = __FILE__, fnc:String = __FUNCTION__){ println("\(file.lastPathComponent):\(fnc)") }
źródło
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)") }
źródło
Swift 3.x +
Jeśli nie chcesz pełnej nazwy pliku, oto szybka poprawka.
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
źródło
Inny sposób rejestrowania wywołań funkcji:
NSLog("\(type(of:self)): %@", #function)
źródło