作者:Anddy Hope丢氢,原文鏈接,原文日期:2016-04-14
譯者:Darren秸苗;校對:Cee;定稿:CMB
如果說 Log 是一種時尚运褪,那你就是時尚設(shè)計師惊楼。
在上一篇文章中,我聊到了如何通過在打印的日志中使用 emoji 表情來幫助你從冗雜的信息中減少認知負荷秸讹。然而檀咙,我給的糟糕的實現(xiàn)并不會讓你對在自己的代碼中使用 emoji 產(chǎn)生強烈的意愿。
這篇文章我將會實現(xiàn)承諾嗦枢,告訴你如何使用比 print
函數(shù) 稍微 復(fù)雜的方法輕量地實現(xiàn)帶 emoji 表情的日志攀芯。
預(yù)算限制
在本文接下來的部分,你會看到:我們會打破 Swift 的命名約定文虏,不過這么做是有理由的侣诺;為了降低替代 print 的成本殖演,我們需要減少敲擊鍵盤的次數(shù);此外使用大寫字母的必要性也需要討論年鸳。不過如果看完后你的認知負荷還是存在的話趴久,那就換成你喜歡的命名吧。
介紹 log
enum log { }
我們使用 enum 而不是 class 和 struct 是有一些理由的搔确。其中一個原因是我們永遠不需要實例化一個 log彼棍。我們使用 case 判斷條件而不是通過函數(shù)判斷,是因為我們想實現(xiàn)一個安全的 log膳算。你很快就會知道我為什么這么說座硕。
Case 的關(guān)聯(lián)值
enum log {
case ln(_ line: String)
case url(_ url: String)
case obj(_ any: AnyObject)
}
有些朋友可能不知道吧,ln
(line)曾經(jīng)在 Swift 中出現(xiàn)過涕蜂,在 Swift 2.0 出現(xiàn)前华匾,println()
曾是替代 print()
打印 log 的主要方式。我也寫了一些其他的例子來證明 log 的擴展性机隙。
在 case 的條件中我們包含了不同的關(guān)聯(lián)值來應(yīng)對不同輸入所對應(yīng)輸出的 log 值蜘拉。同時你也應(yīng)該注意到了我們省略了聲明中的外部參數(shù)的名稱,因為我們使用了 case 的名稱來描述參數(shù)的作用有鹿。
看看我們現(xiàn)在可以做些什么:
print(log.ln(“Hello World”))
// ln("Hello World")
print("Hello World")
// "Hello World"
呃旭旭,的確是可以用的,但是它絕不是一個合適的補充或替代 print 語句的選擇葱跋。原因如下:
- 想要使用它時需要敲多次鍵盤持寄;
- 在原始數(shù)據(jù)外面有多余的內(nèi)容;
- 而且看起來一點都不受人喜歡年局;
- 甚至都沒有用到任何表情符號际看;
- 總而言之它這貨簡直就弱爆了!
所以我們現(xiàn)在需要用一個方法來解決這五件事矢否≈倜觯快上車,帶你到達我之前許諾的終點——日志島僵朗。
自定義操作符
postfix operator / { }
我會假定你們中的大部分人都沒有過實現(xiàn)自定義操作符赖欣。很正常,我也是最近才開始用的验庙,但其實這并不難顶吮。
我們自定義的操作符將會是后綴操作符(postfix)
,因為我們希望它在 log 的代碼后面粪薛,而且同時希望在它的左邊僅有一個輸入悴了。
我選擇使用「/」這個符號,因為它是最接近注釋語法而又不會實際創(chuàng)建注釋的,還因為它是為數(shù)不多的不需要按 shift 鍵進行輸入的操作符湃交。
...我真的開始感覺我就像一個收到預(yù)算限制的政客熟空。
實現(xiàn)
postfix func / (target: log) {
switch target {
case ln(let line):
log("??", line)
case url(let url):
log("??", url)
case obj(let object):
log("??", object)
}
這個實現(xiàn)很像是聲明,但是我們提供了一個函數(shù)體搞莺,增加了要求傳入的參數(shù)為 log
枚舉類型的限制息罗,這就是我所說的寫「更安全的代碼」。此外還有一點也能夠證明「更安全的代碼」才沧,就是 log
聲明時是一個枚舉類型而不是類或者結(jié)構(gòu)體迈喉,因為枚舉類型的 switch 語句一定是完全覆蓋所有判斷條件的。每當我們添加一個新的 emoji 日志類型温圆,我們必須同時在操作符的 switch 語句中包含它挨摸。
private func log<T>(emoji: String, _ object: T) {
print(emoji + “ “ + String(object))
}
最后,我們實現(xiàn)了 log
函數(shù)捌木,這簡單得難以置信油坝。它是私有函數(shù)
嫉戚,因為我們不希望它在我們正在寫的 .swift
文件外部被訪問刨裆。它的第二個參數(shù)是一個泛型,因為我們可能會傳任何類型進去彬檀。
如你所見帆啃,它只是一個簡單地把 emoji 表情和對象用一個空格連接起來的 print 語句。
用起來
log.ln(“Pretty”)/
?? Pretty
log.url(url)/
?? http://www.andyyhope.com
log.obj(date)/
?? 2016–04–02 23:23:05 +0000
Maybe i should use a screenshot here instead?
這樣就做好了窍帝!只需要額外敲兩下鍵盤(字母)努潘,我們已經(jīng)可以成功地從被應(yīng)用和第三方日志塞滿的控制臺中找到特定類型的日志。但事情還沒做完...
性能提升
很多開發(fā)者都忽略了的一個事實是調(diào)用 print 實際上會降低你的應(yīng)用的性能坤学。在調(diào)試過程中代碼中遍布大量的 print 是完全沒有問題的疯坤,但是在上架 App Store 之前,你真的應(yīng)該刪掉它們深浮。
你的意思是我必須每次在提交前要注釋掉所有的 print压怠,然后再取消注釋嗎?——你
預(yù)編譯指令
Xcode 允許我們在每個工程中創(chuàng)建額外的配置飞苇。默認情況下 Xcode 為新工程提供了兩種配置菌瘫,Debug 和 Release。
在模擬器或通過 USB 連接的設(shè)備上運行你的 app 時布卡,Debug 是默認配置雨让;當你打包 app 準備上架時,使用的是 Release 配置忿等。
我們將把我們的 print 代碼用 Debug 預(yù)編譯指令包起來栖忠,這樣我們就不用每次打包時都注釋/取消注釋/添加/刪除所有的 print 了。相反,我們會告訴編譯器「喲庵寞,請注意虚汛,只在非 release 模式下運行這段代碼!」
編譯設(shè)置
- 點擊項目導(dǎo)航圖標皇帮;
- 選擇你的項目名稱卷哩;
- 選擇編譯設(shè)置;
- 搜索 Compiler Flag属拾;
- 展開 Other C Flags将谊;
- 點擊 +;
- 輸入
-D DEBUG
渐白。
最后尊浓,我們將把我們實際的 print 函數(shù)打包進我們剛才設(shè)置的預(yù)編譯指令中。
private func log<T>(emoji: String, _ object: T) {
#if DEBUG
print(emoji + “ “ + String(object))
#endif
}
瞧纯衍!現(xiàn)在你的 print 語句只會在調(diào)試時運行栋齿。你可以通過改變你的編譯配置方案為 Release 再測試運行你的 app,不過不要忘了把它重新改回 Debug襟诸!
Framework瓦堵、Carthage 和 Cocoapods 支持
或許你可能對上面的內(nèi)容很喜歡,而且會想:「如果 Andyy 再提供 Framework歌亲、Carthage 或者 CocoaPods 的支持就更好了」菇用,但是實際上這對 log 的功能性來說沒有好處。
原因是陷揪,如果我提供這三者之一惋鸥,每次你想打 log 的時候,在你使用前悍缠,你都需要將框架導(dǎo)入你的 Swift 文件卦绣,這樣做很傻,因為你在每次使用這個愚蠢的 log 把戲前都需要做一些額外的管理工作飞蚓。這也是為什么那么多 NSLog 的替代品在 Objective-C 下面工作地并不好滤港。
import Log // 看上去就是一坨??
探索與使用
我為你們提供了一個 playground 用來測試文章中寫到的內(nèi)容,同時還提供了一個 log.swift
文件方便你添加到自己的項目中玷坠。示例代碼中有一些額外的案例可以用在日常的開發(fā)中蜗搔。盡情享受吧!
示例代碼已上傳 GitHub.
像往常一樣八堡,如果你喜歡你今天看到的內(nèi)容樟凄,或者已經(jīng)實現(xiàn)了它,請 發(fā)推給我兄渺。我喜歡讀者的反饋缝龄,這會讓我很高興!
本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán)叔壤,最新文章請訪問 http://swift.gg瞎饲。