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

作者: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("✏️", line)
    case url(let url):
        log("🌏", url)
    case obj(let object):
        log("🔹", 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”)/
✏️ 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?

这样就做好了!只需要额外敲两下键盘(字母),我们已经可以成功地从被应用和第三方日志塞满的控制台中找到特定类型的日志。但事情还没做完...

性能提升

很多开发者都忽略了的一个事实是调用 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 // 看上去就是一坨💩

探索与使用

我为你们提供了一个 playground 用来测试文章中写到的内容,同时还提供了一个 log.swift 文件方便你添加到自己的项目中。示例代码中有一些额外的案例可以用在日常的开发中。尽情享受吧!


示例代码已上传 GitHub.

像往常一样,如果你喜欢你今天看到的内容,或者已经实现了它,请 发推给我。我喜欢读者的反馈,这会让我很高兴!

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容