Swift:如何優雅地使用 print()(二)

khlsc402gjq 8年前發布 | 20K 次閱讀 Swift iOS開發 移動開發

作者:Anddy Hope, 原文鏈接 ,原文日期:2016-04-14

譯者: Darren ;校對: Cee ;定稿: CMB

如果說 Log 是一種時尚,那你就是時尚設計師。

在上一篇文章中,我聊到了如何通過在打印的日志中使用 emoji 表情來幫助你從冗雜的信息中減少認知負荷。然而,我給的糟糕的實現并不會讓你對在自己的代碼中使用 emoji 產生強烈的意愿。

這篇文章我將會實現承諾,告訴你如何使用比 print 函數 稍微 復雜的方法輕量地實現帶 emoji 表情的日志。

預算限制

在本文接下來的部分,你會看到:我們會打破 Swift 的命名約定,不過這么做是有理由的;為了降低替代 print 的成本,我們需要減少敲擊鍵盤的次數;此外使用大寫字母的必要性也需要討論。不過如果看完后你的認知負荷還是存在的話,那就換成你喜歡的命名吧。

介紹 log

enum log { }

我們使用 enum 而不是 class 和 struct 是有一些理由的。其中一個原因是我們 永遠 不需要實例化一個 log。我們使用 case 判斷條件而不是通過函數判斷,是因為我們想實現一個 安全 的 log。你很快就會知道我為什么這么說。

Case 的關聯值

enum log {
    case ln(_ line: String)
    case url(_ url: String)
    case obj(_ any: AnyObject)
}

有些朋友可能不知道吧, ln (line)曾經在 Swift 中出現過,在 Swift 2.0 出現前, println() 曾是替代 print() 打印 log 的主要方式。我也寫了一些其他的例子來證明 log 的擴展性。

在 case 的條件中我們包含了不同的關聯值來應對不同輸入所對應輸出的 log 值。同時你也應該注意到了我們省略了聲明中的外部參數的名稱,因為我們使用了 case 的名稱來描述參數的作用。

看看我們現在可以做些什么:

print(log.ln(“Hello World”))
// ln("Hello World")

print("Hello World")
// "Hello World"

呃,的確是可以用的,但是它絕不是一個合適的補充或 替代 print 語句的選擇。原因如下:

  • 想要使用它時需要敲多次鍵盤;
  • 在原始數據外面有多余的內容;
  • 而且看起來一點都不受人喜歡;
  • 甚至都沒有用到任何表情符號;
  • 總而言之它這貨簡直就弱爆了!

所以我們現在需要用一個方法來解決這五件事。快上車,帶你到達我之前許諾的終點——日志島。

自定義操作符

postfix operator / { }

我會假定你們中的大部分人都沒有過實現自定義操作符。很正常,我也是最近才開始用的,但其實這并不難。

我們自定義的操作符將會是 后綴操作符(postfix) ,因為我們希望它在 log 的代碼后面,而且同時希望在它的左邊僅有一個輸入。

我選擇使用「/」這個符號,因為它是最接近注釋語法而又不會實際創建注釋的,還因為它是為數不多的不需要按 shift 鍵進行輸入的操作符。

…我真的開始感覺我就像一個收到預算限制的政客。

實現

postfix func / (target: log) {
    switch target {
    case ln(let line):
        log(":pencil2:", line)
    case url(let url):
        log(":earth_asia:", url)
    case obj(let object):
        log(":small_blue_diamond:", object)
}

這個實現很像是聲明,但是我們提供了一個函數體,增加了要求傳入的參數為 log 枚舉類型的限制,這就是我所說的寫「更安全的代碼」。此外還有一點也能夠證明「更安全的代碼」,就是 log 聲明時是一個枚舉類型而不是類或者結構體,因為枚舉類型的 switch 語句一定是完全覆蓋所有判斷條件的。每當我們添加一個新的 emoji 日志類型,我們必須同時在操作符的 switch 語句中包含它。

private func log<T>(emoji: String, _ object: T) {
    print(emoji + “ “ + String(object))
}

最后,我們實現了 log 函數,這簡單得難以置信。它是 私有函數 ,因為我們不希望它在我們正在寫的 .swift 文件外部被訪問。它的第二個參數是一個泛型,因為我們可能會傳任何類型進去。

如你所見,它只是一個簡單地把 emoji 表情和對象用一個空格連接起來的 print 語句。

用起來

log.ln(“Pretty”)/
:pencil2: Pretty

log.url(url)/
:earth_asia: http://www.andyyhope.com

log.obj(date)/
:small_blue_diamond: 2016–04–02 23:23:05 +0000

Maybe i should use a screenshot here instead?

這樣就做好了!只需要額外敲兩下鍵盤(字母),我們已經可以成功地從被應用和第三方日志塞滿的控制臺中找到特定類型的日志。但事情還沒做完…

性能提升

很多開發者都忽略了的一個事實是調用 print 實際上會降低你的應用的性能。在調試過程中代碼中遍布大量的 print 是完全沒有問題的,但是在上架 App Store 之前,你真的應該刪掉它們。

你的意思是我必須每次在提交前要注釋掉所有的 print,然后再取消注釋嗎?——你

預編譯指令

Xcode 允許我們在每個工程中創建額外的配置。默認情況下 Xcode 為新工程提供了兩種配置,Debug 和 Release。

在模擬器或通過 USB 連接的設備上運行你的 app 時,Debug 是默認配置;當你打包 app 準備上架時,使用的是 Release 配置。

我們將把我們的 print 代碼用 Debug 預編譯指令包起來,這樣我們就不用每次打包時都注釋/取消注釋/添加/刪除所有的 print 了。相反,我們會告訴編譯器「喲,請注意,只在非 release 模式下運行這段代碼!」

編譯設置

  1. 點擊項目導航圖標;
  2. 選擇你的項目名稱;
  3. 選擇編譯設置;
  4. 搜索 Compiler Flag;
  5. 展開 Other C Flags;
  6. 點擊 +;
  7. 輸入 -D DEBUG 。

最后,我們將把我們實際的 print 函數打包進我們剛才設置的預編譯指令中。

private func log<T>(emoji: String, _ object: T) {
    #if DEBUG
        print(emoji + “ “ + String(object))
    #endif
}

瞧!現在你的 print 語句只會在調試時運行。你可以通過 改變你的編譯配置方案 為 Release 再測試運行你的 app,不過不要忘了把它重新改回 Debug!

Framework、Carthage 和 Cocoapods 支持

或許你可能對上面的內容很喜歡,而且會想:「如果 Andyy 再提供 Framework、Carthage 或者 CocoaPods 的支持就更好了」,但是實際上這對 log 的功能性來說沒有好處。

原因是,如果我提供這三者之一,每次你想打 log 的時候,在你使用前,你都需要將框架導入你的 Swift 文件,這樣做很傻,因為你在每次使用這個愚蠢的 log 把戲前都需要做一些額外的管理工作。這也是為什么那么多 NSLog 的替代品在 Objective-C 下面工作地并不好。

import Log // 看上去就是一坨:hankey:

探索與使用

我為你們提供了一個 playground 用來測試文章中寫到的內容,同時還提供了一個 log.swift 文件方便你添加到自己的項目中。示例代碼中有一些額外的案例可以用在日常的開發中。盡情享受吧!

示例代碼 已上傳 GitHub.

像往常一樣,如果你喜歡你今天看到的內容,或者已經實現了它,請 發推給我 。我喜歡讀者的反饋,這會讓我很高興!

本文由 SwiftGG 翻譯組翻譯,已經獲得作者翻譯授權,最新文章請訪問http://swift.gg。

 

來自:http://swift.gg/2016/08/23/swift-pretty-in-print-pt-2/

 

Save

 本文由用戶 khlsc402gjq 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!