3.Swift教程翻译系列——Swift基础知识

英文版PDF下载地址http://download.csdn.net/detail/tsingheng/7480427

Swift是用来开发iOS和OS X应用的新语言,但是许多地方用起来跟C或者OC是差不多的。

Swift提供了C语言和OC的基本数据类型,比如整型用Int,浮点型用Double或者Float,布尔型用Bool,字符串文本用String,Swift还提供了两种集合类型,Array和Dictionary,后面会介绍。

Swift也跟C一样用唯一的变量名来存储与使用数据,还能使用一些值不会变的变量,应该说是常量,比C里面的常量要强大。在涉及到一些值不会发生变化的数据时使用常量类型能让代码更安全整洁。

除了跟C和OC相似的类型之外,Swift还增加了一些OC中没有的类型。比如元组,使用元组可以创建或者传递多个值。函数返回值使用元组就可以返回多个值了。

Swift还增加了可选类型。可选类型的变量要么有个确切值,要么是没有值。有点儿像OC里面值为nil的指针,但是OC里面指针只能用于对象,Swift可选类型能用于任何数据类型。可选类型比OC中的nil指针更安全更好用,Swift很多核心牛逼的特性都要指望他。

可选类型也能说明了Swift是一种类型安全的语言。Swift能让程序员清楚知道自己使用的是什么类型。如果代码中需要一个String对象,类型安全机制可以保证Int之类的非String类型对象被传过来。类型安全机制能让你在写代码的时候就能发现并纠正一些错误。

1.常量和变量

常量跟变量都由名称跟值组成,常量的值一旦设置就不允许再改变。变量就没有这个限制了,只要类型没错就能为所欲为。

常量和变量的声明

常量和变量在使用之前都必须声明。常量用let声明,变量用var声明。这边有个例子用常量和变量来记录用户尝试登录次数。

let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0

这两行代码可以这样翻译:“声明一个叫做maximumNumberOfLoginAttempts的常量,给他赋值为10,然后声明一个叫currentLoginAttempt的变量,给他赋值为0。”

这个例子里面maximumNumberOfLoginAttempts是被声明为常量的,因为最多允许登录尝试次数是固定的,不会变的。而currentLoginAttempt表示用户当前已经尝试的次数,是随着用户登录尝试要增加的,所以要被定义成变量。

声明变量或者常量的时候也可以一行声明多个,中间用逗号分隔。比如 var x = 0.0, y = 0.0, z = 0.0

NOTE 如果代码里面要用到不会改变的值,尽量都用let声明成常量,只有需要改变的才声明成变量。

类型标注

声明变量或者常量的时候还可以加个类型标注,来限定这个变量或者常量可以存储什么类型的值。写法是在变量名或常量名后面加上冒号空格再加存储类型。举个例子,我要声明一个存储String类型的变量,代码就是 var welcomeMessage: String,冒号的意思是“...类型为...”,所以前面的代码可以翻译成:“声明一个类型为String的变量welcomeMessage”。“类型为String”意思是说“可以存储任何的String值”。

welcomeMessage现在可以被赋值,不会报错了。 welcomeMessage = “Hello”

NOTE 实际上这个类型标注可能很少用,如果在声明变量或者常量的时候就给他个初始值,编译器就能自己推断出来变量或者常量的类型是什么了。这个在后面类型安全与类型推断里面会江到。上面这个例子中welcomeMessage没有初始值,所以编译器没有办法推断出来他是什么类型,也就需要用类型标注来指明变量类型了。

变量或常量命名

Swift变量常量命名很自由,甚至可以用中文或者表情字符来命名。

let π = 3.14159
let 你好 = "你好中国"
let 狗狗表情 = "dogcow"

但是名称里面不能包含数学符号,大于小于号,或者保留的(或者非法的)Unicode编码位,或者连接线与制表符。也不能用数字打头,但是后面可以用数字。

变量或者常量的名字不能重复声明,类型也不能变,变量跟常量也不能互相转变。

NOTE 如果你想用Swift关键字同名的名字,你可以在名字前后加上倒引号(好像是数字1前面那个键)就行了,不过要尽量避免使用关键字,除非说是没的选了(比如说领导要求的)。

变量的值可以改成跟现有值相同类型的值。

var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
// friendlyWelcome is now "Bonjour!"

常量就不一样了,常量值一旦设定就不能改了,如果要给常量再赋值,就会报错了。

let languageName = "Swift"
languageName = "Swift++"
// this is a compile-time error - languageName cannot be changed

输出常量和变量

可以使用println函数来输出常量或者变量的值。

println(frientlyWelcome)
//输出“Bonjour”

println是用来输出的全局函数,输出结果最后会自动换行。如果是用Xcode,println函数会把结果输出到Xcode的控制台。(还有另外一个函数print,也是用来输出的,但是print输出的结尾不会自动换行。)

println函数可以输出任何字符串。

println("This is a string")
// prints "This is a string"

println函数还能用来输出更复杂的日志,跟Cocoa的NSLog函数差不多。日志可以包含常量也能包含变量。

Swift使用字符串填补的方式在长字符串中使用常量或者变量。使用方法是用括号把变量名括起来,前面在加个反斜杠,然后直接放入字符串中。

println("The current value of friendlyWelcome is \(friendlyWelcome)")
// prints "The current value of friendlyWelcome is Bonjour!"

NOTE 使用字符串填补时的其他所有选项在后面字符串填补里面会有介绍。

2.注释

使用注释可以在代码中加入一段不被执行的文字。编译器编译的时候会把所有的注释都忽略掉。

Swift的注释跟C的注释非常像,单行注释用双斜杠打头。比如  // 这是一行注释

多行注释用/*开头,*/结尾

/* this is also a comment,
but written over multiple lines */

但是多行注释有一个跟C不一样的地方,Swift的多行注释可以嵌套。你可以先写一个/*开头,然后再写个/*作为内层注释,然后先用*/表示内层注释结尾,再写个*/表示外层注释结尾。

/* this is the start of the first multiline comment
/* this is the second, nested multiline comment */
this is the end of the first multiline comment */

可以嵌套的多行注释能让我们很方便的注释掉一大块儿内容,不用事先去看这块儿内容里面是不是已经有多行注释了。

3.分号

跟许多编程语言不一样,Swift不要求在每一行语句后面加分号,不过你要是想加也可以加。但是如果要在一行写多条语句就必须加分号了。

let cat = "cat"; println(cat)

4.整型

整型数是指没有小数的数字,比如42啊,-23啊之类的。整型要么是有符号的(正数,0,负数)要么是无符号的(正数或者0)。

Swfit的无符号数提供8位,16位,32位以及64位的版本。这些类型的命名方式跟C是差不多的。比如8位的无符号整型是UInt8,32位有符号整型是Int32。跟其他类型一样,这些类型首字母都要大写。

整型范围

你可以通过整型类型的min属性和max属性来获取各自的最小值和最大值。

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

使用上面两个属性得到的数值的类型跟使用的类型是一样的,比如上面得到的minValue和maxValue类型都是UInt8,如果要在表达式里面跟其他变量计算或者比较,那其他的变量类型也要是这个类型。

Int

大部分情况下你不需要去指定整型具体是几位的,Swift提供了另外一种整型类型,Int,这个类型的长度跟程序运行的机器字长一样。32位平台运行,Int长度就跟Int32一样,64位平台运行,Int长度就跟Int64一样。

除非说你一定要使用特定长度的整型,不然尽量用Int来表示整型。这样能提高代码的一致性和通用性。就算是32位平台,Int存储范围是-2147483648到2147483647,这范围足够大了。

UInt

Swift还提供了一种没有符号的整型UInt,跟Int一样长度由程序运行的平台决定。

NOTE 只有当你确实需要使用无符号数的时候采用UInt,不然尽量使用Int,就算你知道要保存的值不会有负数。使用Int能增强代码的一致性和通用性,避免了各种类型数字计算的时候再去类型转换。

5.浮点数

浮点数就是带小数部分的数字。比如3.1415,-273.354。

浮点型能存储的数字范围比整型大得多。并且可以存储比整型数最大值更大的数,和比整型数最小值更小的值。Swift提供两种带符号的浮点数类型。

  • Double:占用64位,当要存储的值非常非常大而且需要非常精确的时候用Double。
  • Float:占32位,当你要用小数但是用不着Double的时候就用Float。

NOTE Double类型提供至少15位小数的精度,Float的小数精度只有6位。选哪种类型要根据你要处理的数据的实际情况。

6.类型安全与类型推断

Swift是一种类型安全的语言。类型安全的语言要让你清楚自己使用的变量是什么类型。如果变量是String类型,就不能赋Int值给他哦。

因为Swift是类型安全的,所以编译器在编译代码的时候要进行类型检查,对于任何类型匹配不正确的地方都会报错。这个特性能让你在开发的时候就发现并纠正很多错误了。

当你要处理各种各样不同类型的数据的时候,类型检查能帮你避免很多错误。但是并不是说你必须在声明每一个常量或者变量的时候就要指定对应的类型。如果你不指定,Swift会自动推断出对应的类型。类型推断可以让编译器在编译的时候通过你提供的值来自动推断出其所对应的数据类型。

因为有了类型推断,Swift里面的类型声明就比C或者OC这样的语言里面少的多了。

当你声明常量或者变量的同时还提供初始值得时候类型推断就非常好用了。通常要在声明变量或者常量的时候给他提供一个字面值。(字面值就好比是个立即数,不需要额外计算的。比如下面例子中的42或者3.14159。)

比如如果你把字面值42赋给一个刚声明的常量,但是不指定常量类型,Swift会推断出来这个常量是Int类型的,因为你提供的初始值是Int类型的。

let meaningOfLife = 42
// meaningOfLife is inferred to be of type Int

如果你用浮点数做初始值,并且不指定类型,Swift推断出来的结果就是Double。

let pi = 3.14159
// pi is inferred to be of type Double

Swift推断小数类型的时候结果是Double而不会是Float。

如果你在表达式里用整数和小数相加,结果推断出来的是Double。

let anotherPi = 3 + 0.14159
// anotherPi is also inferred to be of type Double

字面值3没有明确表示自己的类型,而表达式中出现了Double类型,所以最后推断出来的类型是Double。

7.数字字面值

整数字面值可以用下面几种方式表示:

  • 十进制数字,没有前缀
  • 二进制数字,0b开头
  • 八进制数字,0o开头
  • 十六进制数字,0x开头

比如下面这几个数字的十进制值都是17

let decimalInteger = 17
let binaryInteger = 0b10001 // 17 in binary notation
let octalInteger = 0o21 // 17 in octal notation
let hexadecimalInteger = 0x11 // 17 in hexadecimal notation

小数字面值可以是十进制(没有前缀),护着十六进制(0x开头)。小数点两边都必须有数字。浮点数还有另外一种指数表示方法,十进制浮点数用大写或小写字母E,十六进制浮点数用大写或小写字母P。

对于十进制来说如果指数是exp,就表示用基数乘以10的exp次方:

  • 1.25e2表示1.25乘以10的2次方,或者125.0
  • 1.25e-2表示1.25乘以10的-2次方,或者0.0125

对于十六进制数来说如果指数是ext,就表示用基数乘以2的exp次方:

  • 0xFp2表示15乘以2的2次方,或者60.0
  • 0xFp-2表示15乘以2的-2次方,或者3.75

下面的几个浮点数字面量都是十进制的12.1875

let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0

数字字面值还能加一些其他的格式让人更容易看懂。整数和浮点数都能在前面添加额外的0,还能添加下划线。这些格式都不会影响字面量的值。

8.数字类型转换

要存储数字的时候尽量都用Int,即便是你知道要存储的值不会是负数。如果你每次都用默认的整型类型来定义常量和变量,这样你定义的这些变量跟常量的类型就能跟字面值推断出来的类型一样了,代码通用性就很强。

只有当你必须要用其他类型的整型的时候才去用,比如要在代码上用确切位数来保证性能,或者内存优化或者其他必要的优化。使用指定长度的类型可以帮助你避免一些不小心的值溢出,也可以为数据提供一份隐式的说明。

整型转换

对于整型常量或者变量,不一样的数字类型能存储的数据范围是不同的。Int8类型能存储的范围是-128到127,UInt8可以存储的范围是0到255。赋值的时候如果数据超出这个范围内,编译器会报错。

let cannotBeNegative: UInt8 = -1
// UInt8类型不能存储负数,所以会报错。UInt8 cannot store negative numbers, and so this will report an error
let tooBig: Int8 = Int8.max + 1
// <pre name="code" class="objc">Int8 不能存储超过最大值得数字,所以这里也会报错。<span style="font-family: Arial, Helvetica, sans-serif;">Int8 cannot store a number larger than its maximum value,</span>
// and so this will also report an error

 因为各种数字类型能存储的数据范围不同,所以你就必须要根据具体情况来进行类型转换了。这样能防止隐式转换的错误,还能让代码里的类型转换意图变得清晰。 
 

要转换成其他类型,你需要实例化一个需要转换的类型的实例并且用现有的值给他初始化。拿上面的例子来说,常量twoThousand是UInt6类型,而常量one是UInt8类型,因为类型不一样所以两个常量不能直接相加。下面例子用UInt16(one)来创建一个UInt16类型的实例并用one来初始化,然后用这个值跟twoThousand相加。

let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)

现在加号两边都是UInt16了,所以不会报错了。因为相加的和是UInt16型的,所以常量twoThousandAndOne也是UInt16类型。

类型(值)是调用类型的初始化器并传入一个初始值的默认方式。当然这需要有个前提,就是UInt16有一个接受UInt8参数的初始化器,所以才能用这个方式来用UInt8创建UInt16。所以这里你不能随便传其他类型的,必须是UInt16提供了相应的初始化器的才行。拓展现有的初始化器,添加新的类型参数支持(比方说要支持自己定义的类型)在后面的扩展部分里会介绍。

整型和浮点型的转换

整型和浮点型之间转换必须要显式转换。

let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi=3.14159,所以pi被推断出来时Double类型。pi equals 3.14159, and is inferred to be of type Double
这个例子中常量three的被用来创建另外一个Double类型,这样加号两边的类型才一样。如果不转换,是不能相加的。

反过来也是一样的,Double或者Float类型的值也可以用来初始化一个整型的值。

let integerPi = Int(pi)
// integerPi equals 3, and is inferred to be of type Int

用浮点数来初始化整型数的时候小数部分都会被阉割,比方说4.75转换变成4,-3.9转换变成-3。

NOTE 数字变量或者常量相加的规则跟数字字面量相加规则是不一样的(还记得前面有个3+0.14159吗),字面量3可以直接跟字面量0.14159相加,因为字面量本身还没有一个确切的类型,只有当编译器计算和的时候才会去推断字面量的类型。


9.类型别名

类型别名是指使用现有类型的另外一种方式。类型别名使用关键字typealias来定义。当你想用更合适的方式来使用现有的类型的时候,类型别名就派上用场了。比方说你要在外部代码中使用指定长度的数据。 typealias AutioSample = UInt16

只要你定义了类型别名,那其他只要能用原名的地方都能用别名。

var maxAmplitudeFound = AudioSample.min
// maxAmplitudeFound is now 0

上面例子AudioSample被定义成是UInt16的别名,所以调用AudioSample.min实际上就是调用UInt16.min。

10.布尔型

Swift有一个基本的布尔类型,叫Bool,布尔值是一种逻辑值,要么是true要么是false,Swift提供了两个布尔的常量值,没错,你猜对了,true和false。

let orangesAreOrange = true
let turnipsAreDelicious = false

上面例子中两个常量分别用值true和false来初始化,所以编译器给他们推断出来的类型就是Bool。跟前面声明的Int和Double变量一样,这里你也不需要特别指明是Bool型,当然需要你在创建的时候用true或者false给他们初始化哦。类型推断要让常量或者变量在创建的时候用另一个类型已知的值来初始化,这让Swift的代码很简介也很明了。

当你使用if之类的条件判断语句的时候布尔值就显得很需要了。

if turnipsAreDelicious {
    println("Mmm, tasty turnips!")
} else {
    println("Eww, turnips are horrible.")
}
// prints "Eww, turnips are horrible."

条件判断语句在后面流程控制里面会细讲。

Swift的类型安全机制会保证不能再需要Bool值得地方用其他类型的值来代替。下面的例子就会报错。

let i = 1
if i {
    // this example will not compile, and will report an error
}

下面这样写才是对的。

let i = 1
if i == 1 {
    // this example will compile successfully
}

i==1的比较结果是Bool类型的,所以第二种方式可以通过类型安全检测,类似i==1这样的比较运算会在后面的基本运算里介绍。

跟其他的类型安全的例子一样,这个也能避免一些偶然的错误,保证代码的意思清晰明了。

11.元组

元组能把好几个值放在一起组成一个复合值。元组里面的值可以是任何类型,各个值还不需要类型相同。举个例子,(404, "NotFound")这个元组用来表示一个HTTP状态码。HTTP状态码是指你向一个HTTP服务器请求页面的时候服务器返回的一个特殊值,如果你请求的页面不存在,服务器就会返回404 Not Found。

let http404Error = (404, "Not Found")
// http404Error is of type (Int, String), and equals (404, "Not Found")

(404, "NotFound")这个元组把Int和String结合在一起,返回的HTT状态码有两个值:一个数字,和一段人能看懂的描述。它可以被称为是类型为(Int, String)的元组。

你可以使用任何一组类型来创建元组,你想要任何不同的类型,都能满足你。没有什么可以阻挠你创建(Int, Int, Int)或者(String, Bool)或者任何其他的你想要的元组类型。

你可以把元组的数据解析出来存进常量或者变量,比如下面这样:

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"

如果说你不需要某个位置的值,用下划线来替换那个位置的名字就OK了。

let (justTheStatusCode, _) = http404Error
println("The status code is \(justTheStatusCode)")
// prints "The status code is 404"

或者你也可以用下标来获取元组里面的值。下标从0开始。

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"

我经验不多,不过我感觉这东西跟JS的对象很像啊。

元组用来作为函数的返回值的时候特别有用。比方说有个检索页面的函数,返回(Int, String)类型的元组来表示检索页面成功还是失败。通过返回带有两个值的元组,就能比只返回单个值的函数提供更多信息。更多介绍,请查看多返回值函数。

NOTE 元组对于暂时组装一些相关的数据非常有用。他不需要你去定义一些复杂的数据结构。如果你的数据结果不只是暂时使用比方说还得存盘,这个时候使用创建一个类或者结果体会更合适。更多相关信息请查阅类和结构。

12.可选值

如果说某个值有可能不存在,那你可以使用可选值,可选值表示这里有个值等于多少多少,或者说这里没有值。

NOTE C跟OC里面是不存在可选值的概念的。OC里面跟可选值最接近的特性就是方法要么返回nil要么返回对象,返回nil表示没有可用的对象。但是这只针对对象有效,对于结构体,基本类型或者枚举类型是不适用的。对于这些类型,OC的方法返回了一个特别的值(比如说NSNotFound)来说明这里没有值。这种方式要求调用方法的地方知道这里会返回特殊值,并且要记得去判断。Swift的可选值就没有类型的限制,也就不需要额外特殊额常量了。

这边有个例子,Swift的String类型有个方法叫做toInt,用来把字符串的值转换成Int值。但是,并不是所有的字符串都能转换成数字的,“123"可以转换成123但是”hello, china“显然是转不了的。下面的例子就用toInt方法来吧String转换成Int:

let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
// convertedNumber is inferred to be of type "Int?", or "optional Int"

因为toInt方法是有可能转换失败的,所以他返回的是一个可选的Int,而不是Int。可选Int类型用"Int?"表示而不是"Int"。问号表示这个值是可选的,也就是说变量里面有可能是某个Int值,也有可能什么都没有。(注意这里不可能包含其他比如Bool,或者String类型的值,要么是Int要么什么都没有。)

if语句和强行拆箱

你可以使用if语句来验证一个可选值是不是包含有值。如果有值,返回的是true,如果没有值返回的就是false。

如果你确定可选值有值,你可以在变量名后面加个感叹号来取得里面的值。感叹号的意思相当于:”小样儿我知道你带的有钱,交出来哥要用。“这个就是可选值强制拆箱。

if convertedNumber {
    println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
    println("\(possibleNumber) could not be converted to an integer")
}
// prints "123 has an integer value of 123"

更多if语句的介绍,请参阅控制流。

NOTE 如果用感叹号去获取没有值的可选值,会发生运行时错误。一定要当你确定可选值有值的时候才使用感叹号。想想你鼓起勇气打劫了个穷光蛋,一毛钱没捞着还进去了。

可选值绑定

你也可以用可选值绑定来验证可选值里面是不是有值,通过这种方式可以让可选值暂时存储在一个临时的常量或者变量里。可选值绑定可以用在if或者while的条件语句中判断可选变量里面是不是有值,并且顺便把值取出来放到常量或者变量里面。if跟while在控制流里面介绍,一般有点儿基础的应该都可以跳过了。

if中使用可选值绑定是下面这样的

if let constantName = someOptional {
    statements
}

那么上上面那个例子就能用可选值绑定来代替强制拆箱了。

if let actualNumber = possibleNumber.toInt() {
    println("\(possibleNumber) has an integer value of \(actualNumber)")
} else {
    println("\(possibleNumber) could not be converted to an integer")
}
// prints "123 has an integer value of 123"

代码翻译为:”如果possibleNumber.toInt返回的可选值里面有值,那么定义一个可选常量actualNumber,值就是方法返回的值“。

如果转换成功,常量actualNumber就能在if的大括号里面用了,而且actualNumber已经用转换方法返回的值初始化了,所以就没有必要再用感叹号去获取常量的值了。这个例子中actualNumber只是简单的用来输出转换的结果。

在使用可选值绑定的时候可以用常量也可以用变量。如果你想在if第一个大括号里修改actualNumber的值,就用if var actualNumber代替,然后可选值包含的值就是个变量而不是常量了。

nil

如果你要把一个可选变量变成没有值的状态,给他赋值为ni就可以了。

var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value

NOTE nil不能用来给非可选变量或者常量赋值,如果某个变量或者常量有可能会没有值,一定要给他声明成对应的可选类型。记住是问号哦。

如果你定义一个可选常量或者变量的时候没有提供默认值,那他的值会被自动设为nil。

var surveyAnswer: String?
// surveyAnswer is automatically set to nil

NOTE Swift的nil跟OC里面的nil不太一样。在OC里面nil是一个不指向任何对象的指针,而在Swift里面nil不是指针,而且说这个地方没有值。任何类型都能用nil,而不仅仅是对象类型。

隐式拆箱可选值

上面说的,可选值是说可以没有值的常量或者变量。可选值可以用if语句来检测是不是有值,也可以用可选绑定来拆箱并且获取其中的值。

有时候有的可选值里面很明显总是会有值的,在这种情况下就没有必要每次使用的时候都去检查来拆箱获取值,因为我确定他总是会有值得。这种可选值被称为隐式拆箱可选值。定义这种类型要在类型后面加感叹号,而不是问号。

当某个可选值被定义的时候就被赋值,而且以后都能确定他总是会有值,这个时候隐式拆箱可选值就可以使用。最开始使用隐式拆箱可选值的地方时在类初始化的地方,更多内容在无引用和隐式拆箱可选值属性里面介绍。

隐式拆箱可选值也就是一种可选值,但是还能像非可选值一样来使用,而不想要每次使用的时候都去拆箱。下面举个例子说明可选字符串与隐式拆箱可选字符串的区别。

let possibleString: String? = "An optional string."
println(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string."

let assumedString: String! = "An implicitly unwrapped optional string."
println(assumedString) // no exclamation mark is needed to access its value
// prints "An implicitly unwrapped optional string."

你可以认为隐式拆箱可选值是一种拥有自动拆箱权限的可选值。声明可选变量的时候类型后面加感叹号就是隐式拆箱可选变量,就不用每次使用的时候都在变量名后面加感叹号了。

NOTE 如果你试图访问一个没有值的隐式拆箱可选变量,会产生运行时错误,就像你在一个没有值得可选变量后面加个感叹号一样。

你还可以像使用普通可选值一样使用隐式产想可选值。比如说用If判断其是否有值

if assumedString {
    println(assumedString)
}
// prints "An implicitly unwrapped optional string."

NOTE 如果说可选值以后有可能会变成nil,就不要使用隐式拆箱可选。如果变量生命周期内有可能需要检测是否为nil就使用普通的可选。

13.断言(Assetions)

可选类型可以让你检测值是否存在,然后处理值不存在的情况。但是在有些情况下,如果值不存在就没办法进行,或者有值但是这个值不符合条件。这种情况下你可以触发断言来结束执行,从而可以调试为什么值不存在。

使用断言调试

断言是指在运行期间检测一个逻辑值是否为true。也就是说断言断定那个条件是true。你可以使用断言来保证程序执行的时候只有当满足了某个条件的时候才继续往下执行,如果条件表达式计算结果为true,程序照常执行,如果结果为false,就不再执行了,应用也就退出了。

如果你在调试环境中运行代码并且触发了断言,那你可以清楚的看到哪里的条件没通过,并且可以查看当断言触发的时候应用时什么状态。断言还可以接受你提供的一些调试信息。通过调用全局函数assert来使用断言。第一个参数需要是范围true或者false的表达式,第二个参数的信息可以在表达式返回false的时候输出。

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

上面例子如果age>=0返回true的话代码还会继续执行,也就是说age是非负数的时候。如果age是负数,age>=0就是false了,这个时候断言就触发了,应用终止。

注意第二个参数不能使用字符串填补。不过第二个参数可以省略,比如asset(age >= 0)

什么时候要用断言

如果说某个地方你一定需要满足什么条件才能继续执行的时候就可以用断言。其中包括以下场景:

在使用下标语法的时候数字下标的值不能太大也不能太小。

调用函数的时候如果传递非法参数函数就不能完成任务。

有个可选值当时是nil,但是后面代码的执行需要他有值。

NOTE 当某些条件达不到的时候断言会让应用终止,让应用程序终止肯定不是最好的方式。但是在开发阶段还是保证那些条件被注意到的有效的方式。产品发布了就不要这样做了。

本章完。下章地址: 4.基本运算符

你可能感兴趣的:(ios,swift)