Swift 中自定义Log
前言
在使用Objective-C开发过程中,我们经常要自定义Log,原因很简单:
- 在Debug模式里的log打印,可以帮助我们更好的调试代码,在Release模式里面,用户没有必要看到Log的打印;
- OC中NSLog 会占用很大的内存资源。
通常在OC中,自定义Log写在pch文件中,通过宏定义。
在Swift中,没有宏这个概念了,我们该如何解决呢?
几个问题
允许我卖个关子,先不谈,debug还是release该怎么自定义Log。先谈一下,我们打印的时候遇到的问题。根据问题来一步步解决
1、Swift中print
函数,不会再占用很大的资源,但是在release模式下,确实没有必要打印Log,其实我想说,Swift 中print确实做了很多优化,但是也存在一些问题,看如下代码
print("123")
123
123
我在分别在两个函数里,打印了"123"字符串,可是我并不知道,"123"到底是在哪打印的,在哪个文件或者在哪个函数中,一脸懵逼
所以我想知道我在哪个文件中打印的这句话,Swift可以这样搞:
let file = #file
print(file)
结果:/Users/bh/Desktop/test/test/ViewController.swift
这样就可以把具体哪个文件打印出来了,就是那个绝对路径。
绝对路径很烦,因为前面那些xxx我根本不需要,所以我优化了一下,如下:
let file = #file
let fileName = (file as NSString).lastPathComponent
print("\(fileName)-123")
结果:
AppDelegate.swift-123
ViewController.swift-123
很明显,我知道了在哪个文件中打印了123。
2、我虽然知道了在哪个文件中打印了123,但是如果放在同一个文件中的两个方法里面呢?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let file = #file
let fileName = (file as NSString).lastPathComponent
print("\(fileName)-123")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let file = #file
let fileName = (file as NSString).lastPathComponent
print("\(fileName)-123")
}
ViewController.swift-123
ViewController.swift-123
还是区别不出来,接下来我进一步优化,有两种方式,一种是
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let file = #file
let fileName = (file as NSString).lastPathComponent
let funcName = #function
print("\(fileName):[\(funcName)]-123")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let file = #file
let fileName = (file as NSString).lastPathComponent
let funcName = #function
print("\(fileName):[\(funcName)]-123")
}
}
打印结果:
ViewController.swift:[viewDidLoad()]-123
ViewController.swift:[viewWillAppear]-123
还有另一种(个人偏爱这一种):
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let file = #file
let fileName = (file as NSString).lastPathComponent
print("\(fileName):(\(#line))-123")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let file = #file
let fileName = (file as NSString).lastPathComponent
print("\(fileName):(\(#line))-123")
}
打印结果:
ViewController.swift:(19)-123
ViewController.swift:(27)-123
这种方式,是告诉咱们,在多少行打印,简洁。
3、接下来的问题是,我们不能每个方法里面都写这些代码,显得不专业,需要抽出一个方法来
func BHLog(file: String, line: Int) {
let fileName = (file as NSString).lastPathComponent
print("\(fileName):(\(#line))-123")
}
然后调用时候,BHLog(file: #file, line: #line) 这个样子,更烦了
我们接下来,利用Swift中的 参数默认值解决:
func BHLog(file: String = #file, line: Int = #line) {
let fileName = (file as NSString).lastPathComponent
print("\(fileName):(\(line))-123")
}
BHLog()
4、好像只剩下一下问题了,就是我们要打印的内容,我们不只是要打印String类型,可能是Int、Double或者是对象类型,所以我们需要再加个参数。
func BHLog<T>(_ message: T, file: String = #file, line: Int = #line) {
let fileName = (file as NSString).lastPathComponent
print("\(fileName):(\(line))-\(message)")
}
泛型<T>,它代表着我们可以用T来代替实际类型,函数名后跟的那个 <T> 是函数定义的一个占位类型名,并不会查找T的具体类型。
这样就解决了。
5、剩下最后一个问题,我们有很多的类,不能够在每个类里都调用,这个函数,所以,我们利用Swift的全局函数,在任意一个类里面写个全局函数,就在所有的类中,可以调用了,我是写了个Global.swift 文件,你也可以卸载Appdelegate.swift中。
最后小尾巴
说了这么多,如何在Swift中,debug打印,而release中不打印呢,请继续看:

func BHLog<T>(_ message: T, file: String = #file, line: Int = #line) {
#if DEBUG
let fileName = (file as NSString).lastPathComponent
print("\(fileName):(\(line))-\(message)")
#endif
}
这样release就不会打印了,而在debug模式中会打印
结束,美滋滋!