#Thinking in Swift
从Objective-C转到Swift,我们往往脑袋里还带着旧的一套编程套路。为了利用Swift写出更优雅,更健壮的代码。让我们用初心者的心态来学习新的编程范式,新的可能。
##1.拥抱Optional
。哲学: 一个值要么有值,要么就是optional。
Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This restriction enables you to catch and fix errors as early as possible in the development process.
Swift引进了一个新的概念Optional
,以及相关的一系列语法:
?
与!
声明Optionalif let
Optional bindingguard
as?
与as!
try?
Optional的核心在于类型安全,在于和Nil做斗争。在于在运行前就处理好所有值为空或不为空的情况,如果有错误的话,直接在编译的时候就给出error,不等到运行的时候才crash。
在Swift的世界里,如果我们不声明一个对象为Optional,则它一定是有值的。这一点是非常有价值的,避免了我们对空对象进行操作。虽然在Objective-C中对空对象发送消息不会导致crash。但是有许多情况下对空对象操作会导致Crash,比如向数组插入空对象等许多操作操作。(详情查阅:Crash in Cocoa)
更重要的是,我们更希望达到一种状态,就是我操作对象和数据的时候,我能够确信它不为空。这种哲学避免了许多冗杂无用的判断Nil操作,同时也大大减少了忘记判断nil导致的crash。
那Swift究竟通过什么途径来保证一个对象如果不是Optional,他就一定有值呢?
-
如果我们使用了没被初始化的变量和常量,编译器会抛出error。
var testString:String print(testString) //error: variable 'testString' used before being initialized
-
类和结构体的实例在创建时,一定要为所有存储型属性设置初始值。我们可以在
initializer
或是定义属性的时候为其设置默认值,否则编译器会抛出error.class testClass { var a:String init(){ } // error:return from initializer without initializing all stored properties }
由此我们也引出了optional
的概念。Optional表示一个值可能为空。要么有值,要么为空(nil)。
那么这时候你可能会问,在Objective-C也是这样,一个对象要么有值,要么为nil。
从最简单的语法入手:
var optionalInt:Int?
-
首先,在OC中,nil只针对对象而已,对于结构体,枚举类型,基本的C类型来说,是没有nil的。我们不能直接判断它们是否有值。在OC中,nil是一个指向不存在对象的指针,在Swift中,nil不知指针,它是一个确定的值,用来表示值为空。 (事实上,nil是一个枚举值)
而Swift的Optional让我们能明确地标注一个值有没有可能为空。并且值的类型没有限制。
-
Swift的Optional Binding机制确保我们在使用Optional值时先判断值是否为空。
在Objective-C中,判空操作不是强制和必须的。判空是一个良好的习惯,但是因为没有约束和规范。很多时候判空操作都被遗漏了,导致了许多潜在的问题。
但在Swift中,r
比较绕的一点:
let optionalLet:String?
var optionalVar:String?
//标记为optional的let,一定要在使用前赋值,要么永远为nil,要么永远有值
//标记为optional的var,不需要要在使用前赋值,因为它可能有时有值,有时没值
if let unwarp = optionalLet{
//error: variable used before being initalized
}
if let unwarp = optionalVar{
//OK
}
##2.学习泛型。抽象的魅力。
泛型编程其实简单来说,就是让我们写出不局限于单一类型的代码。
举个最简单的例子:交换。对比以下两种写法,一种是只针对Int类型的交换。而我们用泛型改写后,适用于其它所有类型。
func oldSwap(inout a:Int ,inout _ b:Int){
let temp = a
a = b
b = temp
}
func genericSwap<T>(inout a:T,inout _ b:T){
let temp = a
a = b
b = temp
}