改用swift来思考

改用swift来思考

现有代码库 + 你的头脑 + Swift。 怎么会错呢?

原文链接: Switching Your Brain to Swift

  • 原文日期: 2015/08/17
  • 译文日期: 2015/09/04
  • 译者:ray16897188

本文原基于360iDev 2015的一次谈话。等有视频之后我会贴上连接。与此同时,何不看看我在elsewhere上其他的Swift文章,以及我Twitter的主页呢?

完美的情形当然是从零开始的一个100% Swift的项目。如果你能这么做,很棒!但对与我们中的那些手里已经有现成代码库,而且有点儿想试试Swift的人来说,我们能从哪里开始?

为什么?

退一步:你为什么想用Swift去写代码呢?很多原因:Swift是新星;Swift有更好的语法(开始口水战了);Swift是Apple指引给我们的新方向。

将来,Swift的绝伦程度还会继续增加,并会成为大众首选的,有最完善的技术支持的,写OSX和iOS代码最简便的一种语言。

Swift是未来之路,就这么明了。那怎么做才能开始用Swift的方式去思考呢?

Swift的方式

有太多要考虑的事情了,但我们从两个大的方面说起:安全性和值语义(value semantics)。

安全性

Objective-C里的Nil棒极了。你可以给那个东西一直发消息, 好似明天是世界末日,运行时就会一直提供回应。

然而Swift中的Nil却是另一个很不同的怪物。通常来讲类型系统(type system)会把你从试图调用空函数或者访问空属性中挽救出来,阻止你这么干。但你能绕过类型系统,而这么做和在C语言中解引用一个空指针一样糟糕:在运行时你会被友善的捕获,然后你的app会崩溃。

Swift中一切都关乎类型安全。一个String是一个String,那它就是一个String。此时根本就没nil什么事儿。多想想C++中的引用而非C中的指针,因为引用永远也不会是nil。

可选类型

有了可选类型,nil就又回来了。一个可选类型的String可以确实是一个String,或者是nil。你必须做检查,每一次都要。

或者不做检查:你可以强制将这个可选类型变量拆包。或者将它换成一个隐式解析可选类型(implicitly unwrapped optional),这意味着它有些复杂的劣势,但可以当非可选类型一样去使用 - 直到它是nil的时候,app就崩溃了。

(所有的都拆包!)
(所有的都拆包!)

Cocoa里有太多可选类型,这意味着你每用其中一个,就得去检查里面是什么。

这就是一个大的思维转变。其中的思路是:你不应该留下任何偶然因素让发送的消息为nil。你应该知道,一个强类型系统中,某种东西要么是nil,要么就有值。

如果在运行时有不确定性,就做检查。不要强制去拆包。

把可选类型想成是一个盒子:这个盒子要么没有值(nil),要么就有值。但是你在强制拆包它之前总要先去检查一下。

(你得问:可选类型的盒子里面是啥?)
(你得问:可选类型的盒子里面是啥?)

还有很多其他展示Swift安全性的例子:构造器,更少量的未定义行为(less undefined behavior),内存安全。Nil的安全性是总会出现的一种。

值类型

值类型在Swift中随处可见。没什么新东西 - Objective-C就有像NSInteger和类似CGRect的结构体这样的基元(primitives)。但其绝大多数 - NSString,NSArray等等 - 都是类(classes),因此是引用类型。

Swift中则完全相反,如果你扫一眼头文件的话会发现标准库中有80多个结构体,只有4个类。

String,numbers和集合类型在Swift中都是值类型。这意味着如果你有一个可变的Swift String(是结构体)并把它传给一个函数,你获得的是一个拷贝(copy)。重复一遍,这并非一个吓人的新概念:我们在Objective-C中已经做了很久的copy和mutableCopy。这里大的转变是对于多数常见类型来说这是新的缺省行为。

不幸的是,如果你在Swift中用结构体写了些很棒的代码,在Objective-C中你是不能回访它们的。这就把我们带到了下一个话题:桥接。

桥接

Swift理所当然的被设计成了能与Objective-C良好协同工作。这基本上是一个必要的,无需争论的事实,因为Cocoa是为Objective-C而建立。所有这些Cocoa的API必须能够从Swift调用,这意味着你自己的Objective-C的类也可以良好的桥接到Swift中。

有个问题:从Swift开始,加入Objective-C代码,然后想在Objective-C中调用你的Swift代码。

从Swift到Objective-C

有太多的Swift特性完全不能桥接到Objective-C里,比如Swift自己的结构体和增强的枚举类型。这意味着如果你用Swift里所有最酷的特性写出来的最新最强的framework,其中绝大多数并不能被Objective-C访问到。

即使你给自己做限制,仅用Swift中那些可兼容Objective-C的特性去写,你也不能从Objective-C的类派生出一个用Swift写的子类。你可以遵循table View或collection view的模式,并用delegate和布局对象(layout objects)来规避这个问题,但是如果你的API是要被继承从而派生子类的话,还是要时刻记住这一点。

Swift中任何东西在Objective-C中都默认不可见。
如果你把你的class和protocol标记了@objc,那它们就可以在Objective-C中用了。动态调节器(dynamic modifier)也暗含着@objc的标注,让被标记的东西在Objective-C中可用,但它使那些被标记了dynamic的属性或者方法采用的是Objective-C的动态分发(dynamic dispatch)。

(Swift&Objective-C)
(Swift&Objective-C)

如果你想用swizzle之类的东西,你就需要用dynamic;仅仅给它标识@objc还不足以保证objc_msgSend()能被使用,因为方法是有可能被去虚拟化(devirtualized)或者被内联了。

重复一下,这仅仅对那些可兼容的特性有效。你自己写的Swift枚举类型中的方法并不适用。如果你枚举类型不是由Int型所构建,那就兼容不了。

Objective-C 到 Swift: 可空性(Nullability)

从Objective-C转到Swift有很多好消息。为了促进这个转换过程,在Objective-C中你要给你的属性,参数和返回值类型加上标注(annotation)。

  • _Null_unspecified (default) – 桥接到一个Swift隐式解析可选类型(implicitly-unwrapped optional)。
  • _Nonnull – 该值不可以是nil;桥接到一个常规的引用。
  • _Nullable – 该值可以是nil;桥接到一个可选类型。

如果你给你的Objective-C加了标注,你就会顺利的将类型桥接到Swift中。即使你没碰过Swift,你用Objective-C的时候这些标注也会在代码补全后出现。如果你告诉编译器一个方法的参数是_Nonnull的,然后传进去一个nil,你就会得到一个合理的编译器警告。

开始为代码加标注是很好的做法。使用现有的API的时候标注会帮到你,你开始用Swift的时候也会让你加快速度。

Objective-C 到 Swift: 轻量泛型(Lightweight Generics)

轻量泛型是Swift 2的新特性。集合类型NSArray,NSDictionary(对值类型)和NSSet可以包含任何旧的NSObject类型。

这意味着大量的类型转换(casting)。Objective-C中没有这个问题,但是记住:Swift是关乎安全性的。正确的转换涉及到大量的检查。你不应该强制的做类型转换,而应该先测试。

现在有了泛型,意味着你可以在Objective-C中这样写:

NSArray<NSString *> * _Nonnull

这是一个会包含NSString对象的NSArray。有了可空(nullability)的注释,你能看见它还说了这个array不会为nil,你总会得到一个array。如果你了解Java或者C++就会熟悉此处的泛型语法。
然后桥接到Swift就会是这样:

[String]

一个非常清晰的Swift String数组。
小的补充说明:轻量泛型只能应用于基本集合类:arrays,dictionaries和sets。

在浑水上架桥

我会建议从零开始新建一个Swift的项目 - 100%完全的Swift。如果你有第三方的frameworks,它们是Swift写的还是Objective-C写的就不会有太多影响 - 你能调用其中的任何一种。
如果你有一个现有的代码库,而且你想要开始引入Swift:那就尝试将桥接按照从Objective-C到Swift的方向进行。比如view controllers和views的具体实例在Swift中就运行的很好;它们继承自NSObject,如果需要的话你是可以从Object-C中访问到它们的。

(金门大桥)
(金门大桥)

但是对所有其他的来说:纯Swift泛型,由非整型,嵌套类型,结构体构成的枚举类型等等 - 就需要等到你身处于一个100% Swift世界中的那一天了。别被落下,这一天会比你想象的来的更早。

在那天之前,接着写能够友善兼容Swift的Objective-C的代码并保持对Swift最新技术的认知吧。有太多的资源会帮助你完成过渡。

资源

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

推荐阅读更多精彩内容