为什么独立开发者(不)需要关心Swift【下】

Swift是苹果在WWDC 2014上突然宣布的一种新编程语言。Swift自身很多有趣的特性已经引起不少开发者的追捧。关于Swift火热的最直接证据就是:github上的Swift开源项目在一周中已经逼近700个

上一次灯塔实验室分享了一些关于Swift的有趣观点。Swift很讨巧,给人以一种简洁、有力的第一观感。看着其他小伙伴已经一日千里地奔着Swift去了,你已经跃跃欲试了?别急,今天来给大家降降温。须知硬币都有正反面,Swift在给予开发者便利的同时,也精心准备了诸多深坑供大家玩耍。

BpJiibvCEAA72by

~我们已经可以扔掉Objective-C了么?~

Optional:安全与便利的悖论

Swift以带问号的语法引入了optional类型,主责是将未初始化变量以一种主动的形式迫使开发者知晓。而开发者若想使用optional,即“允许未初始化”的变量时,必须使用感叹号来进行取值,也就是所谓的unwrap。

var illegalString :String = nil // 编译错误
var legalString :String? = nil

func genString(bar :Int) -> String?
{
    if bar > 30
    {
        return "abc"
    }
    else
    {
        // 如果可以返回nil,必须强制返回类型为optional
        return nil
    }
}

var a: String = genString(50)! // 必须进行取值操作,否则类型不匹配
var b: String? = genString(0)

苹果在设计Swift的时候,将安全摆在了一个相当重度的位置,从而牺牲了语言的随性。寄希望于Swift能更像脚本语言那样随意编写的同学,可能会在optional这里感受到来自语言设计者的恶意。

第二参数名:另一个名字还是历史的包袱?

这个问题还算比较良性。我们通常写带参数的函数是这样

//这样很好,与世无争
func foobar(a: Int, b: String) -> String {...}

但是,皇上您还记得大明湖畔的夏雨荷么?

- (instancetype)initWithBytes:(const void *)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding

多么令人怀念的老时光。Swift为了要兼容Objective-C/Cocoa,也搞出了类似的东西,称之为“外部参数名”:

class Matrix
{
    func doMultiplication(str :String, 
                          fromData data1 :Int[], 
                          withData data2: Int[])
    {
        // do something
    }
}

let m = Matrix()
m.doMultiplication("My Matrix", fromData:[1,1,0,1], withData:[1,1,2,3])

从第二个参数开始,每个参数还有内外两个名字?这种丑到爆的语法真是历(nan)史(yi)沉(tu)疴(cao)啊╮(╯▽╰)╭

初始化:安全第一,好用第二

毫无意外地,Swift是一门(带少量函数式编程特性的)面向对象语言。同样毫无意外地,Swift类必须安装有初始化函数init。秉承前面optional带来的安全理念,开发者对于init的编写也有诸多规定,也就演化出了特定初始化函数和便利初始化函数,以及随之而来的convenience关键字。

class Item
{
    let name :String
    
    init(givenName name:String)
    {
        self.name = name
    }
}

var item = Item(givenName: "GeneralItem")

class Grenade : Item
{
    let explosive :Int
    init(givenName name: String, withExplosive explosive: Int)
    {
        self.explosive = explosive
        // 必须在子类初始化完毕所有成员后,再调用
        // 基类的构造;否则编译错
        super.init(givenName: name) 
    }
    
    convenience init(explosive: Int)
    {
        // 所谓的便利构造函数只能调用子类的特定构造函数,
        // 并不能涉及到基类构造;否则编译错
        self.init(givenName:"MyGrenade", withExplosive:explosive)
    }
}

let grenade1 = Grenade(givenName: "MyGrenade", withExplosive: 500)
let grenade2 = Grenade(explosive: 300)

写个初始化函数这么麻烦?为了安全,就得这么麻烦!其实不只是初始化,为了安全,连简单的switch结构也必须写default,这安全与好用的功与过,就全凭使用者来评判了。

ARC:自动引用计数带来的烦恼

苹果从Objective-C时代就引入了辅助对象生命期管理的自动引用计数(ARC)机制。Swift也一并继承了ARC。虽然ARC有轻量化、行为可预测、没有垃圾回收机制卡顿的优势,但也带来了很要命的问题:无法自行解决循环引用问题——从而引起内存泄露。

内存泄露难以跟踪、忽隐忽现又破坏力极大,它无疑是程序员最恐怖的梦魇。无奈之下,Swift引入了两个关键字weak和unowned,修饰不会自动增加引用计数的变量,来解决循环引用问题。

class Person
{
    let name: String
    var buff: Buff?
    
    init(name: String)
    {
        self.name = name
    }
    
}
// 施加在人物身上的buff技能
class Buff
{
    let id: Int
    weak var target: Person?
    
    init(id: Int)
    {
        self.id = id
    }
}
var me = Person(name: "Jon Blow")
var buff = Buff(id: 42)
me.buff = buff

然而游戏中buff是跟着人走的。没有人就谈不上buff,这就意味着Buff类中target设置为optional是不合适的。更好的做法是使用unowned。

class Person
{
    let name: String
    var buff: BetterBuff?
    
    init(name: String)
    {
        self.name = name
    }
    
}
class BetterBuff
{
    let id: Int
    unowned let target: Person
    
    init(id: Int, withTarget target: Person)
    {
        self.id = id
        self.target = target
    }
    
}
var me = Person(name: "Jon Blow")
me.buff = BetterBuff(id: 42, withTarget:me)

这里友情提醒一句,解决普通对象之间的循环引用只是战斗的开始。Swift是门现代语言,函数和闭包都是一等公民,所以后面还有闭包之间的循环引用等着勇敢的程序员们。

其他

另外还有一些语言特性看上去新奇,但基本上只能算是Objective-C的翻版,例如protocol和extension,基本上是复制了Objective-C的protocol和category,并没有为解放程序员的双手带来更多好消息。 Screenshot-2014-06-04-10.22.29 值得一提的倒是外围特性:Playgrounds。Playgrounds并不是Swift语言自带的功能,而是Xcode 6中一种新工程形态。如果不是发布会上那惊鸿一瞥,Playgrounds恐怕会湮没在众多新特性的海洋之中。Playgrounds是促进苹果整个生态系统的一个巨大进步,它为Swift配置了动态语言的专利——交互式环境。而且还像matlab这类软件一样,Playgrounds提供数值视觉化效果,这类难能可贵的“所见即所得”,让游戏的细调的工作变得如捏橡皮泥搬简单。虽然Playgrounds之后会否发展成为一个单独的编辑器,我们不得而知,但Swift+Playgrounds+Sprite Kit毫无疑问已经向Corona这类二线游戏引擎产生了致命的冲击——一个飞速发展的生态圈内,是容不下弱者的。

说起来,Xcode 6 beta中的Playgrounds还非常地不稳定,没有足够的勇气不要轻易尝试哦~

未来

讲了这么多Swift的坏话,回过头来我们还是要认真评估一下它的未来:尽管Swift有着这样那样的妥协、不足,但它仍将是2014年增长速度最快的语言,没有之一,就像沉默十几年的Objective-C在iPhone开发热潮兴起之时,一瞬间成为了世界的宠儿。且不说,Swift所依赖的开源编译系统LLVM,也是目前编译器界最受瞩目的项目。他的创造者Chris Lattener,也就是那个WWDC上演示Playgrounds的默默无闻的天才少年,已经多次被ACM协会授予编译器、语言、系统方面的奖项。他在编译器、语言生态系统的远见卓识,让LLVM在原先强大的业界标准——GCC编译系统面前迅速崛起。不用猜,目前我们Xcode使用的编译系统正是LLVM

行文至此,我们可以初步得出结论:Swift是一门脱胎自Objective-C的语言,带有浓厚的Objective-C/Cocoa的痕迹,也遵循了前辈的一些设计哲学,但同时拥有强大的现代语言特性。在权衡了易用性和安全性的前提下,做到了一定的动态语言的功能——不能说是尽善尽美。它的底层由强大且开放的LLVM支撑,外围又有Xcode所带来的Playgrounds让开发者立即上手。凭借苹果的开发生态圈,Swift必将以极快的速度取代Objective-C成为苹果平台开发的首选。至于Swift是否有望扩展到其他平台,WWDC并没有给予我们答案。参考苹果之前的作风,恐怕其底层库Cocoa移植的可能性不大。但由于LLVM的存在,Swift以开源编译器的形态,舍弃Cocoa而出现在各家平台上的可能性还是很大的。

封烨。曾以技术发展为己任的游戏行业人,有过不知天高地厚的技术演讲和文章,多年后转变思路,认为无法单纯通过攻克薄弱技术环节来改善行业种种弊病,于是投身于独立游戏运动。前椰岛游戏的联合创始人,上海Game Jam和Global Game Jam在国内的首批倡导者,现灯塔实验室创始人。

Tagged as: , , ,

Categorized in: 技术talk

Posted on

One thought on “为什么独立开发者(不)需要关心Swift【下】

  1. Skulle nästa vilja säga att det är omöjligt att gå upp i vikt med HCLF. Har flera gånger provat utan att lyckats speciellt bra. Det är &qtfa;oun" inte lätt att vräka i sig 10-20 bananer och annan frukt, råkost och nästan kilovis med ris, potatis och sen händer i princip inget med vikten.

Leave a Reply

电子邮件地址不会被公开。