iOS8 Day-by-Day :: Day 1 :: Swift学习指南
这篇文章是iOS8 Day-by-Day系列的一部分,你可以查看完整的系列目录:iOS8 Day-by-Day 系列文章
介绍
今年的WWDC大会真让人难以置信,除了宣布iOS8之外,他们还引入了一个新的编程语言Swfit。这跟objective-c这种强类型的语言有很大的不同,它包括了现代语言一些常见特性。
怀着拥抱一切新东西的心情,这系列的博客将使用swfit。有大量的信息关于如何学习swfit语言,以及如何与cocoa交互——事实上下面这两本官方的书籍不能错过:
这两本书的中文版见 github: Welcome-to-Swift
同时可以参考苹果的Swfit官方博客 以及其它swfit 资源
正因为有如此多关于Swfit的资源,本篇文章不会去介绍所有swfit的知识,而是介绍首次使用Swfit容易遇到的一些重要的陷阱以及潜在的问题,特别是和系统框架相关部分。
本章的实例程序github访问地址:github.com/ShinobiControls/iOS8-day-by-day/
初始化
关于初始化,swfit 和 objective-c 有很大的不同如下:
objective-c代码:
1 2 3 4 5 6 7 |
|
对应的swfit代码如下:
1 2 3 4 5 |
|
objective-c 的初始化方法负责 创建和返回self 而swfit没有return 语句,这就意味着swfit没有任何方式去返回nil对象。 nil 对象在objective-c中通常表示一个失败的初始化,这显然在接下来发布的swfit更新中有可能改掉。
可变对象与不可变对象
可变或不可变对象的概念对Cocoa开发者已经非常熟悉如:NSArray 和 NSMutableArray 在swfit中,let关键字来定义不可变对象,如:
1 2 |
|
这就意味这不能重新赋值给let关键字指定的实例。实例的引用能不能重新赋值取决于对象的类型,如果一个实例是value type(如结构体)引用了let关键字指定的实例,改实例依然是不可变的,如果引用是一个class实例, 则改引用是可变的,具体看下面的例子:
1 2 3 4 |
|
如果使用var关键字定义一个变量struct1 ,你将得到如下行为:
1 2 3 4 |
|
你可以改变属性u,因为它是通过var关键字定义的,同时也可以变量struct1本身,同样是因为通过var关键字定义的,而不能改变属性t,因为它是通过let关键字定义的,让我们看下使用let关键字定义的一个struct:
1 2 3 |
|
现在,不仅是struct2不可变,而去属性u也是不可变的,这是因为结构体是一个 value type
对于一个class上述行为则有点不同,如下:
1 2 3 4 5 6 7 8 9 |
|
通过var关键字定义一个class实例,行为和使用objective-c类似:
1 2 3 4 |
|
现在不仅引用自己是可变的,而且所有通过var关键字定义的属性也是可变的,只是通过let关键字定义的属性是不可变的。作为比较我们来看下使用let关键字定义的实例:
1 2 3 |
|
现在自己的引用就是不可变的了,但是var关键字定义的属性是可变的,这是因为一个class是 reference type
上述行为时比较容易理解的,因为大部分有引用类型的语言书籍都有详细的解释,当使用swfit 集合类型是上述行为就有点困惑,一个 NSArray 是一个reference type,也就是说当你创建一个NSArray实例时,就是创建了一指针指向数组所在的一块内存区域(根据objective-c 的定义),如果你根据上面介绍的”reference type”不难推理出NSArray的实例也是可变的,实际上,如果要创建一个可变数组,再objective-c中完我们要使用NSMutableArray Swfit 数组与此不同,它使用value types 来代替 reference types, 也就意味着在swfit中的行为类似一struct而不是一个class,因此关键字 let 或者var 不仅可以指定变量是否可以重定义,而且还可以指定一个数组实例是否可变。 通过 var定义的数组既可以重新赋值也是可变的:
1 2 3 |
|
通过 var定义的数组两者都不可以:
1 2 3 |
|
哦,my god,都晕了,这不仅完全改变了我们对集合可变的认识,而且混谣了上面说的两个概念的区别,这个有个可能在后面swfit语言的发展中会修改,因此保持关注swfit语言的定义。
结论:由于arrays 是 值类型,所以它们通过拷贝来传递,NSArray实例是通过引用来传递,如果在一个方法中传递一个swfit array ,它将对这个数组进行拷贝,至于是深拷贝还是潜拷贝取决于数组中存储的对象。
强类型和任意对象(AnyObject)
强类型是swfit一个很大的特性,使用它可以写出更安全的代码,这使得objective-c在运行时的异常可以在编译时捕获。
这是很强大,但是在objective-c 中我们经常用到 id类型,swfit中对应的就是AnyObject,AnyObject 感觉不像swfit的风格(un-swfit-like),它允许你调用任何它能找到的方法,但是这将在运行时导致异常。实际上,它的行为和objective-c的id非常相似,区别在于,如果AnyObject对象上没有相应的属性或方法,它将返回nil:
1 2 |
|
为了更像Cocoa APIs中的 swfit 风格(swfit-like),下面是很常见的代码模式:
1 2 3 4 5 6 |
|
如果你完全确定传递一个字符串,你没有必要做如上的代码保护,可以直接这样写:
1
|
|
Swift 协议(protocol)
Protocol 在swift中很容易理解如下:
1 2 3 |
|
一个常见的情况就是检测一个对象是否符合指定的协议,你可能写下:
1 2 3 |
|
然而它会导致错误,因为为了检查是否符合某个协议,改协议必须是objective-c 协议,即通过 @objc来指定的协议:
1 2 3 4 5 6 7 |
|
如果Swift类继承自Objective-C的类,则它里面的方法和属性都能够作为Objective-C的选择器使用。而如果不是Objective-C的子类,需要使用@objc属性修饰。
枚举
枚举在swfit中变化很大,不仅可以枚举有关联的值(可以使不同类型),而且还方法也可以枚举。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
真是强大,可以如下使用:
1 2 3 4 |
|
总结
Swfit 是一门功能强大的语言,掌握它的最佳实践、惯用方法以及模式需要一段时间,这篇文章列出了一些从objective-c到swfit常见的困惑.