NSCalendarUnitYearMattt Chester Liu 🚩🌱

从两年前 一篇关于 NSIndexSet 的小文章 发布到现在,NSHipster.com 已经走过了两个年头。每周我们都会发表一篇新文章,探讨 Objective-C 或者 Cocoa 当中一些不为人知的话题(除了几周例外),这些文章的读者覆盖超过 180 个国家,人数高达数百万。

这篇文章实际上是我们的第 101 篇文章,意味着 按照电视工业的标准,这个站点已经可以在电视上广播了。(湖南卫视我们来了!)

我们用蛋糕来庆祝一下:

很可爱吧?让我们看看它在代码里面是什么样子:

var cakePath = UIBezierPath()
cakePath.moveToPoint(CGPointMake(31.5, 32.5))
cakePath.addCurveToPoint(CGPointMake(6.5, 66.1), controlPoint1: CGPointMake(31.5, 32.5), controlPoint2: CGPointMake(6.9, 46.3))
cakePath.addCurveToPoint(CGPointMake(6.5, 66.5), controlPoint1: CGPointMake(6.5, 66.2), controlPoint2: CGPointMake(6.5, 66.3))
cakePath.addLineToPoint(CGPointMake(6.5, 95))

...

等等,这是什么,Objective-C?操作 UIBezierPath,不是什么突破性质的黑科技,不过通过一些代码,我们可以让这件事变得简单一些。

通过 自定义操作符,我们来在这个蛋糕上加入一些语法“糖”,怎么样?

infix operator ---> { associativity left }
func ---> (left: UIBezierPath, right: (CGFloat, CGFloat)) -> UIBezierPath {
    let (x, y) = right
    left.moveToPoint(CGPointMake(x, y))

    return left
}

infix operator +- { associativity left }
func +- (left: UIBezierPath, right: (CGFloat, CGFloat)) -> UIBezierPath {
    let (x, y) = right
    left.addLineToPoint(CGPointMake(x, y))

    return left
}

infix operator +~ { associativity left }
func +~ (left: UIBezierPath, right: ((CGFloat, CGFloat), (CGFloat, CGFloat), (CGFloat, CGFloat))) -> UIBezierPath {
    let ((x1, y1), (x2, y2), (x3, y3)) = right
    left.addCurveToPoint(CGPointMake(x1, y1), controlPoint1: CGPointMake(x2, y2), controlPoint2: CGPointMake(x3, y3))

    return left
}

看到了吗? ---> 替代了 moveToPoint+- 替代了 addLineToPoint+~ 替代了 addCurveToPoint。这个声明同时还去掉了对于 CGPointMake 的冗余调用,转而使用简单的坐标元组。

Swift 对于开发者组织代码这个方面,提供了非常大的灵活性。这种“最小约束”思想的代表特性之一,就是可以添加自定义的前缀,中缀和后缀操作符。 Swift 语法约束自定义操作符由下面这些字符当中的一个或者多个组成(在操作符不和保留字符冲突的情况下,例如用于 optional 值的 ?!

/ = - + * % < > ! & | ^ . ~.

自定义操作符是一个强大的工具,可以用来精简逻辑,减少冗余和不必要的重复,等等等等。和诸如模式匹配和链式语法这些语言特性结合起来,可以用于创建完美适用于当前问题的 DSL。

只是…你懂得,不要让这种力量冲昏头脑。

在加入完整的 Emoji 支持之后(let 🐶🐮),对于从 Objective-C 转过来的开发者来说,自定义操作符差不多是最闪亮的新特性了。和其他的闪亮新特性一样,它注定要毁掉一些人的三观。

Swift 崭新特性的危害——戏剧化展示

场景:旧金山,2017年

灰胡子:今天我接手了一些旧的 Swift 代码,我发现了这行代码——我对$灯发誓——它长这样 😾 |--~~> 💩

语法哥摇了摇头

灰胡子:这货到底是什么意思?这是一坨翔在放大招,还是要被开瓶器教做人 ?

语法哥:的确,如果这不算是哲学难题,我不知道还有什么是了。

灰胡子:不管它了,这个语句实际上是重新载入了附近的餐馆。

语法哥:哥们儿,AFNetworking 的 4.0 版本真的变得诡异了。

灰胡子:是啊。

这个寓言告诉我们一个道理:有节制地使用自定义操作符和 emoji

(或者管他呢,下面的示例代码完全忽略了这个建议)

// Happy 2nd Birthday, NSHipster
// 😗💨🎂✨2️⃣

var 🍰 = UIBezierPath()
🍰 ---> ((31.5, 32.5))
     +~ ((6.5, 66.1), (31.5, 32.5), (6.9, 46.3))
     +~ ((6.5, 66.5), (6.5, 66.2), (6.5, 66.3))
     +- ((6.5, 95))
     +~ ((8.5, 96.9), (6.5, 96.1), (7.4, 97))
     +- ((92, 93.1))
     +~ ((94.2, 93), (93.1, 93), (94.1, 93))
     +~ ((94.4, 91), (94.3, 93), (94.4, 92.1))
     +~ ((94.4, 64.5), (94.4, 91), (94.4, 65.5))
     +~ ((92.4, 61.5), (94.4, 62.5), (92.4, 61.5))
   ---> ((92.5, 89.4))
     +~ ((90.5, 91.4), (92.5, 90.4), (91.6, 91.3))
     +- ((10.5, 94.9))
     +~ ((8.5, 93.1), (9.4, 94.9), (8.5, 94.1))
     +~ ((8.5, 83), (8.5, 93.1), (8.5, 88.4))
     +- ((92.5, 79.1))
     +~ ((92.5, 89.4), (92.5, 84.5), (92.5, 89.4))
🍰.closePath()

🍰 ---> ((92.5, 76))
     +- ((8.5, 80))
     +~ ((8.5, 68.2), (8.5, 74.2), (8.5, 68.7))
     +~ ((9.5, 67.1), (8.5, 67.3), (9.5, 67.1))
     +- ((91.5, 63.5))
     +~ ((92.5, 64.4), (91.5, 63.5), (92.5, 63.5))
     +~ ((92.5, 76), (92.5, 64.9), (92.5, 70.3))
🍰.closePath()


var 📍 = UIBezierPath()
📍 ---> ((46, 47.5))
     +~ ((41.5, 52), (46, 50), (44, 52))
     +- ((41.5, 52))
     +~ ((37, 47.5), (39, 52), (37, 50))
     +- ((37, 19.8))
     +~ ((41.5, 15.3), (37, 17.3), (39, 15.3))
     +- ((41.5, 15.3))
     +~ ((46, 19.8), (44, 15.3), (46, 17.3))
     +- ((46, 47.5))
📍.closePath()


var 🔥 = UIBezierPath()
🔥.miterLimit = 4

🔥 ---> ((45.8, 8.4))
     +~ ((41.7, 14), (45.8, 12.5), (44, 14))
     +~ ((37.6, 8.4), (39.4, 14), (37.6, 12.5))
     +~ ((41.8, 1), (37.6, 4.3), (41.8, 1))
     +~ ((45.8, 8.4), (41.8, 1), (45.8, 4.3))
🔥.closePath()


UIColor.blackColor().setFill()
🍰.fill()
🔥.fill()

UIColor.whiteColor().setFill()
UIColor.blackColor().setStroke()
📍.fill()
📍.stroke()

我和你一样感到惊讶,这东西居然能过编译。

太差劲了。


无论如何,NSHipster,两周年快乐!

谢谢你们,在你们的帮助下,过去这几年的经历对我来说简直美好的难以置信。接下来的日子,我会做好本职工作,继续我们的航程。


除非另有声明,本文采用知识共享「署名-非商业性使用 3.0 中国大陆」许可协议授权。