前面三篇笔记通过一些示例展示了Swift的一些特性,粗略地介绍了它的语法和特色,从这一篇笔记开始,将正式系统地介绍Swift的语法和特性了。
Swift是一门为iOS和OSX开发准备的全新语言,但是它和C以及Objective-C有很多相似的地方。
Swift给所有的C语言基本类型和Objective-C类型提供了自己的包装类型,比如用Int标识integers,用Double和Float标识浮点值,String标识文本数据,Swift也提供两个主要的集合类型提供了自己的版本:Array和Dictionary。
和C一样,Swift通过唯一的名称来使用变量保存和引用值,Swift也大量运用了不可改变的值,即所谓常量,不过比C语言中的常量更为强大。常量的运用贯穿了Swift,使得代码更安全,更简洁。
除了那些熟悉的类型,Swift也增加了之前没有出现的新类型,比如元组(tuple),元组可以让你创建和传递成组的值,可以用元组将很多值作为一个复合值从函数返回。
Swift也引入了可选类型(optional type),用来处理那些可能不存在的值。它就以为着“这里有一个值,它等于x”或者“这里没有这个值”
可选类型和OC中的nil相似,不过它适用于任何类型,而不仅仅是类对象。它也更安全,很多Swif的核心特性的实现都用到了它。
可选类型是Swif是一种类型安全语言的例证,如果你指定某个变量的类型为String,那么你就不能给它赋Int类型的值了。
常量和变量
前面已经介绍过常量和变量了,编写Swift代码时,如果确定某个变量的值不会再更改,应该尽可能用let来将其声明为常量。常量和变量的名称可以几乎是任何字符,比如
let π = 3.14159 let 你好 = "你好世界" let ???? = "dogcow
当然,名称还是会有一些约束,比如不能有箭头、横线、数学符号、空格,也不能以数字开头等。
声明变量或者常量之后,就不能在用同样的名字声明了,也不能将常量转换成变量,或者反过来。
如果要用Swift语言用过的名字声明变量,用(`)符号将关键字包起来,当然这是不推荐的,除非万不得已。
类型声明
可以显示地指明变量或者常量的类型名称告诉编译器这个变量的类型。不过在实际开发中,很少需要这样声明类型,因为只要在声明变量或者常量的时候给它赋初始值,编译器就能推测出该变量或常量的数据类型了。如果没有提供初始值,则需要指明变量类型。
分号
在Swift中,并不要求在每一句结尾时加上分号,当然加上分号也不会报错,但是,如果是在一行里边有多个表达式,则在每个表达式后面必须加上分号。
整型(Integers)
Swift提供8、16、32和64位的有符号和无符号整型,它们和C语言类似,比如8位无符号整型为UInt8,整型的范围可以通过属性获取,比如:
let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
通常情况下,不要这样写,Swift提供了通用的整型类型Int,它为根据实际运行平台调整范围。与之类似的是UInt,适应平台的无符号整型。
整型变量可以用多种进制表示,十进制则直接书写,二进制需要加0b前缀,八进制需要加0o前缀,十六进制需要加0x前缀
浮点数
浮点数用来存储带有小数点的数,浮点数存储的范围比整型要大得多,Swift提供两种浮点数类型:
Double代表64位的浮点数
Float代表32位的浮点数
Double可以精确到小数点后15位,Float只有6位。根据实际使用情况选择其中一种使用,如果两种都适合,推荐使用Double。
浮点数可以用十进制(无前缀)和十六进制(0x前缀)表示,小数点两边必须都有数字。也可以用指数表达(十进制用e,十六进制用p):
1.25e2 相当于 1.25 × 100, 或者 125.0 十进制的科学表达式中,基数是10
0xFp2 相当于 15 × 4, 或者 60.0 十六进制的科学表达式中,基数是2
数值的字面形式可以有很多格式,前面可以加任意数的缩进或者0,或者加下划线,这些都不会对整型和浮点型产生影响。
不同的数值类型有不同的存储范围(比如Int8存储-128到127,UInt8存储0到255),将范围之外的值赋给该变量编译器会报错,数值类型不会隐式地自动转换,你必须显示地转换他们的类型(通过初始化器):
let twoThousand: UInt16 = 2_000 let one: UInt8 = 1 let twoThousandAndOne = twoThousand + UInt16(one) //这里本身UInt16和UInt8是不能相加的
整型和浮点型之间的类型转换也必须显示地指明,从整型到浮点型以及从浮点型到整型都需要。
类型别名
通过typealias关键字来为已经存在的类型定义新的名字。
typealias AudioSample = UInt16
一点定义了别名,就可以像用原始类型名一样在任何地方使用它了
Booleans
Swift有一个基础的布尔类型,叫Bool,并且提供了两个布尔型常量true和false。
Swift的类型安全机制阻止将非布尔型值向布尔型做隐性转换,比如:
let i = 1 if i { //改成 if i==1 则可 // this example will not compile, and will report an error }
元组
元组将多个值组合成一个复合值,这些值并不需要都是统一类型的。比如(404, "Not Found")就可以。
元组也可以被分解为任意的常量或变量,这些变量或常量可以像通常那样被访问:
let http404Error = (404, "Not Found") let (statusCode, statusMessage) = http404Error println("The status code is \(statusCode)") // prints "The status code is 404" println("The status message is \(statusMessage)") // prints "The status message is Not Found
如果只需要元组的某一部分值,其他部分可以被忽略的话,那么在分解元组的时候可以用下划线:
let (justTheStatusCode, _) = http404Error println("The status code is \(justTheStatusCode)") // prints "The status code is 404
同时,也可以通过数字序号来访问元组的成员值:
println("The status code is \(http404Error.0)") // prints "The status code is 404" println("The status message is \(http404Error.1)") // prints "The status message is Not Found
在定义元组时,也可以为每个元素指定名字,此后就可以通过名字来访问这些元素了:
let http200Status = (statusCode: 200, description: "OK") println("The status code is \(http200Status.statusCode)") // prints "The status code is 200" println("The status message is \(http200Status.description)") // prints "The status message is OK
元组在临时组织数据的时候非常有用,而不用每次都创建复杂的高级数据结构。但是如果数据需要长久或者复杂地组织起来,用类或者结构更合适。
可选项(Optionals)
在C和OC中并没有可选项,与其最接近的就是OC中函数可以返回一个对象或者nil,nil意味着不存在这个对象。但是nil只对对象适用,C语言基本类型以及OC其他类型都不适用。对于其他类型,OC一般在需要的时候都返回特殊的值(比如NSNotFound),这也以为这函数必须知道应该返回的类型,Swift则没有这个要求,可选项适用于任何类型。
举个栗子:Swift中的String类型有一个toInt方法,用来将String转换为Int,但是并不是所有的String都可以转换为Int的:
let possibleNumber = "123" let convertedNumber = possibleNumber.toInt() // convertedNumber is inferred to be of type "Int?", or "optional Int"
nil
将optionals的值设为nil表示这个值不存在。
注意:nil并不能用来给非可选项赋值。如果常量或者变量可能会在某些情况下没有值,则将其设为可选项。可选项值在声明时如果没有赋初始值,则自动被设为nil
Swift的nil和OC中的nil不一样,OC中的nil表示指向不存在的对象的指针,而Swift的nil不是指针,它只是代表某个类型的值不存在。
可以通过是否与nil相等来判断可选项值是否存在。比如:if convertedNumber != nil 这样。
如果你确定某个optionals值一定有值,可以通过在optionals值名称后面加上感叹号来访问其实际值,这就是optionals值的强制展开:
if convertedNumber != nil { println("convertedNumber has an integer value of \(convertedNumber!).") } // prints "convertedNumber has an integer value of 123.”
注意:如果optionals值不存在,而又通过强制展开访问它的值,会触发运行时错误。
可选绑定(Optional binding)
通过可选绑定,来确定某个可选项是否有值,如果有,则将其赋给某个临时常量或者变量,一般通过if和while来实现:
if let constantName = someOptional { statements }
if let actualNumber = possibleNumber.toInt() { //这里不仅判断了是否可以toInt,而且如果成功,就已经将其赋值给常量actualNumber了
println("\‘\(possibleNumber)\‘ has an integer value of \(actualNumber)")
} else {
println("\‘\(possibleNumber)\‘ could not be converted to an integer")
}
可选绑定既可以是常量,也可以是变量,并且在一个If表达式中可以有多个可选绑定。
隐式展开可选项(implicitly unwrapped optionals)
如前所述,optionals意味着某个常量或者变量允许“没有值”,并且可以通过if语句来判断是否含有值,然后有条件地展开。有的时候,通过代码的结构,可以确定optionals在拥有某个值之后就一直保持存在值的。这时,就不需要在每次获取它的值时都判断是否有值而有条件展开,这种optionals被称为隐式展开可选项,在书写的时候,在类型后边加上一个感叹号(如:String!)而非问号(如:String?)。
隐式展开的optionals在其初次定义之后就确认有值,并且在之后可以确定一直有值的时候非常有用。它的主要作用在Swift中是在类的初始化中,后面会有介绍。
隐式展开的optionals本质上仍然是个optionals,但是可以像不可选项值(nonoptional value)一样被使用,而不需要在每次获取值时都展开。以下示例展示了在获取值时可选string和隐式展开可选string的区别:
let possibleString: String? = "An optional string." let forcedString: String = possibleString! // 需要感叹号 let assumedString: String! = "An implicitly unwrapped optional string." let implicitString: String = assumedString // 不需要感叹号
可以认为隐式展开的optionals是被允许在使用的时候自动展开的optionals。不是在每次使用的时候在其后边加上一个感叹号,而是在声明它的时候就在类型名后边加上一个感叹号。
如果访问一个没有值的隐式展开optional,会触发一个运行时错误,这和访问没有值的普通optional一样。
在不确定其后它的值是否会变为nil时,不要用implicitly unwrapped optionals,一般情况下都直接用optional。
断言
可选项是用来检查一个值是否真的存在,以便做出相应处理,有时,在某个值不存在的时候,程序没有办法继续进行下去,此时可以用断言来中断程序,从而可以进行debug。
断言是一个运行时的检查,断言首先设定某个条件,如果运行时条件满足,则正常运行,如果条件不满足,则程序中断,应用被终止。如果实在调试模式,此时可以精确知道程序的状态和中断位置。
通过全局函数assert来编写断言:
let age = -3 assert(age >= 0, "A person‘s age cannot be less than zero")//后边这条描述语句可以被省略 // this causes the assertion to trigger, because age is not >= 0
断言会导致应用被终止,它不是尽可能避免出现错误的方式,它是在错误很有可能出现的地方,在正式发布之前的开发阶段就确保这些错误会被发现并且被明确锁定。