Swift:漂亮的 print() Pt.2

mile 7年前發布 | 8K 次閱讀 Swift Apple Swift開發

時尚日志,由你做主

在 之前的文章 中,我們討論了在輸出日志中使用 emojis 的好處,它可以幫助我們更好的去消化和吸收大量的信息,不過我提供的實現方式并不怎么樣,沒有足夠多的例子供你將其應用在自己的代碼中。

我將遵守之前的約定繼續討論這個話題,向你展示如何使用 emojis 來實現輸出日志的功能,只需在 print 函數上再多花費一點兒工夫。

節省成本

在接下來的文章中,我會打破 Swift 的命名規范,這樣做我可不缺理由。為了降低新方案的成本, 要在盡可能減少鍵盤敲擊次數的情況下達到同樣的目標,比如字母大小寫和標題大小寫的問題。不管怎么樣,如果看到文章的最后,你還在為一些細節而糾結的話, 你絕對應該把它們改成你想要的樣子。

介紹 log

enum log { }

這里使用枚舉類型代替類或結構的原因很多。原因之一是,我們永遠不需要實例化一個日志。選擇枚舉而不是函數,是想確保實現一個安全的日志輸出方案。不用著急,一會你就會明白我所說的“安全”的含義了.

枚舉成員與值關聯

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

可能有些人還不知道 ln (line) 曾經在 swift 語言中出現過。 print() 在 Swift 2.0 之后替代了 println() , 且主要用于日志輸出。我在這里舉了一些例子來解釋 log 枚舉的可擴展性。

要先為每一個枚舉值設置關聯值,畢竟得現有東西才能輸出日志吧?請注意,這里忽略了參數標簽,因為已經使用參數名稱來描述函數的參數了。

看一下目前的情況吧:

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

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

嗯,看樣子似乎是完成了。但這看起來并不是一個可以替代 print 的方案。主要原因有這些:

  • 還是要敲擊很多次鍵盤
  • 除了原始信息外還有許多不必要的內容
  • 外表不怎么樣
  • 沒有一個 emojis
  • 千言萬語,就一句:“這方案太糟糕了”

現在需要完善上面的五個問題, 以便實現之前定下的目標.

自定義運算符

postfix operator / { }

先假定你們大多數人在這之前都沒有遇到過自定義運算符的需求。沒關系,我也是最近才用上這個功能, 不過用的也不是太多.

要創建一個 postfix 后置運算符,展示的內容會出現在運算符的左側,想讓它出現在日志代碼的后面, 只用敲擊一次鍵盤就能實現。

選擇 / 符號是因為它最接近注釋符號但不會真正產生注釋,另外它也是少數幾個不用 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)
}

這段代碼看起來像聲明,有代碼主體(body), 增加了在約束,確保自定義操作符接收的參數是 log 枚舉值,這在一定程度上符合我所說的的“安全代碼”。“安全代碼”這個概念還體現在使用枚舉替代類或結構體,因為枚舉中的 switch 一定會把所有情況都檢查一遍。這樣,每次想在輸出日志中添加一個新的 emoji 時, 也必須將其添加到操作符中的 switch 語句里。

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

終于得到了這個看似非常簡單 log 函數。它是一個私有函數,可不被 .swift 文件之外的任何東西訪問到,另外它的第二個參數是一個泛型,這個參數能夠接受任意類型的值。

正如你所看到的一樣,這是一個相當簡單的打印語句,把 emoji 表情和對象用空格連起來。

用起來

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 方法會降低 app 的性能。如果含有 print 的代碼散落在程序的不同地方, 在 debug 的時候還是可以接受, 可是要把 app 上傳到 AppStore 時,最好還是移除這些內容。

“你是在說,每一次我都必須在提交 App Store 前注釋掉所有的 print 語句, 然后再在 debug 的時候把它們恢復回來么?” —— 你

預編譯標識符

可以用 Xcode 給工程創建配置文件, 在默認情況下 Xcode 會為每個工程提供兩個配置文件 : Debug 和 Release.

在使用模擬器或用 USB 連接真機時,默認模式是 debug,用手機打開從 AppStore 下載的 app 時,默認模式是 relsase。

把剛才寫好的代碼放入到用于標識 debug 狀態的預編譯標識符里, 這樣就不用在每次打包的時候對這些代碼進行注釋/恢復/增加/刪除等操作。相當于告訴編譯器:“Hi,哥們,除了 release 模式下, 你都得運行這段代碼!”

Build Settings

  1. 點擊 Project Navigator 圖標
  2. 點擊 Project 名稱
  3. 點擊 Build Settings 按鈕
  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 才會生效。把 build configuration scheme 設置改為Release,運行 app,這樣就可以檢測之前的操作是否成功,當然別忘了檢測完把狀態切回到 Debug 模式。

做一個支持 Carthage 或 Cocoapod 的框架

讀到這, 也許會想:“這些個點子太好了, 如果 Andyy 將這些功能弄成一個…”,但事實是這樣做并不好。

原因就是, 假如我提供了上面三種方式中的任意一種, 那么每當你想利用它做日志輸出的時候,你就必須在 Swift 文件里引入這個庫, 這樣做實在太傻了, 還需要做一些額外的操作來管理它們。這也是為什么許多 NSLog 的替代品在 Objective-C 中表現不好的原因。

import Log // 這看起來像坨 :hankey:

探索和把玩

我專門提供了一個 playground 文件,能夠讓你測試一下今天所讀到的全部內容,如果想使用這個文件,只需要將 log.swift 文件拖入到工程中即可。另外在示例代碼中會有一些額外的枚舉值, 或許你會發現這些額外的例子對你的日常工作很有用, 如果是這樣的話,拿走不謝!

示例代碼 可以在 Github 上下載到.

就像之前一樣, 如果你喜歡今天讀到的內容或者親手實現了它,請記得發我一個 tweet 。很渴望聽到你們的聲音, 讓我很受用.

 

 

來自:http://swift.gg/2017/02/21/swift-pretty-in-print-pt-2/

 

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