《The Swift Programming Language 中文版》阅读笔记

概要

项目地址:https://github.com/numbbbbb/the-swift-programming-language-in-chinese
在线阅读:http://wiki.jikexueyuan.com/project/swift/

Swift 是一种新的编程语言,用于编写 iOS,OS X 和 watchOS应用程序。Swift 结合了 C 和 Objective-C 的优点并且不受 C 兼容性的限制。Swift 采用安全的编程模式并添加了很多新特性,这将使编程更简单,更灵活,也更有趣。Swift 是基于成熟而且倍受喜爱的 Cocoa 和 Cocoa Touch 框架,它的降临将重新定义软件开发。

Objective-C 开发者对 Swift 并不会感到陌生。它采用了 Objective-C 的命名参数以及动态对象模型,可以无缝对接到现有的 Cocoa 框架,并且可以兼容 Objective-C 代码。在此基础之上,Swift 还有许多新特性并且支持过程式编程和面向对象编程。

基础部分

TODO 需要重新回顾的部分(可选绑定,隐式解析可选类型,错误处理, 断言<2015-10-12 Mon>

基本运算符

  • 一元运算符对单一操作对象操作(如-a)。一元运算符分前置运算符和后置运算符,前置运算符需紧跟在操作对象之前(如!b),后置运算符需紧跟在操作对象之后(如i++)。
  • 二元运算符操作两个操作对象(如2 + 3),是中置的,因为它们出现在两个操作对象之间。
  • 三元运算符操作三个操作对象,和 C 语言一样,Swift 只有一个三元运算符,就是三目运算符(a ? b : c)。
  • 空合运算符(Nil Coalescing Operator),空合运算符(a ?? b)将对可选类型a进行空判断,如果a包含一个值就进行解封,否则就返回一个默认值b.这个运算符有两个条件:
    • 表达式a必须是Optional类型
    • 默认值b的类型必须要和a存储值的类型保持一致
  • 空合运算符是对以下代码的简短表达方法:
a != nil ? a! : b 

几个需要注意的地方:

  1. 与 C 语言和 Objective-C 不同,Swift 的赋值操作并不返回任何值。
  2. 在对负数b求余时,b的符号会被忽略。这意味着 a % ba % -b 的结果是相同的。
  3. 除非你需要使用i++的特性,不然推荐你使用++i和–i,因为先修改后返回这样的行为更符合我们的逻辑。
  4. 复合赋值运算没有返回值,let b = a += 2这类代码是错误。这不同于上面提到的自增和自减运算符。
  5. Swift 也提供恒等===和不恒等!==这两个比较符来判断两个对象是否引用同一个对象实例。
  6. 三目运算提供有效率且便捷的方式来表达二选一的选择。需要注意的事,过度使用三目运算符会使简洁的代码变的难懂。我们应避免在一个组合语句中使用多个三目运算符。
  7. 半开区间的实用性在于当你使用一个从0开始的列表(如数组)时,非常方便地从0数到列表的长度。
  8. 为了一个复杂表达式更容易读懂,在合适的地方使用括号来明确优先级是很有效的,虽然它并非必要的。

字符串和字符(Strings and Characters)

String是例如"hello, world","albatross"这样的有序的Character(字符)类型的值的集合。通过String类型来表示。 一个String的内容可以用变量的方式读取,它包括一个Character值的集合。
创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。 字符串连接操作只需要简单地通过+符号将两个字符串相连即可。与 Swift 中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你也可以在字符串内插过程中使用字符串插入常量、变量、字面量表达成更长的字符串,这样可以很容易的创建自定义的字符串值,进行展示、存储以及打印。
尽管语法简易,但String类型是一种快速、现代化的字符串实现。 每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种 Unicode 表示形式(representations)。你也可以在常量、变量、字面量和表达式中进行字符串插值操作,这可以帮助你轻松创建用于展示、存储和打印的自定义字符串。

注意: Swift 的String类型与 Foundation NSString类进行了无缝桥接。就像 AnyObject类型 中提到的一样,在使用 Cocoa 中的 Foundation 框架时,您可以将创建的任何字符串的值转换成NSString,并调用任意的NSString API。您也可以在任意要求传入NSString实例作为参数的 API 中用String类型的值代替。 更多关于在 Foundation 和 Cocoa 中使用String的信息请查看 Using Swift with Cocoa and Objective-C (Swift 2.1)。

字符串字面量

初始化空字符串

可以通过检查其Boolean类型的isEmpty属性来判断该字符串是否为空.

字符串可变性

字符串是值类型

  • Swift 的String类型是值类型。 如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。 值类型在 结构体和枚举是值类型 中进行了详细描述。
  • Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。 很明显无论该值来自于哪里,都是您独自拥有的。 您可以确信传递的字符串不会被修改,除非你自己去修改它。
  • 在实际编译时,Swift 编译器会优化字符串的使用,使实际的复制只发生在绝对必要的情况下,这意味着您将字符串作为值类型的同时可以获得极高的性能。

使用字符

  • 您可通过for-in循环来遍历字符串中的characters属性来获取每一个字符的值。
  • 通过标明一个Character类型并用字符字面量进行赋值,可以建立一个独立的字符常量或变量。
  • 字符串可以通过传递一个值类型为Character的数组作为自变量来初始化。

连接字符串和字符

  • 字符串可以通过加法运算符(+)相加在一起(或称“连接”)创建一个新的字符串。
  • 您也可以通过加法赋值运算符 (+=) 将一个字符串添加到一个已经存在字符串变量上。
  • 您可以用 append() 方法将一个字符附加到一个字符串变量的尾部。

字符串插值

  • 字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。 您插入的字符串字面量的每一项都在以反斜线为前缀的圆括号中。
  • 插值字符串中写在括号中的表达式不能包含非转义反斜杠 (\),并且不能包含回车或换行符。不过,插值字符串可以包含其他字面量。

Unicode

Unicode 是一个国际标准,用于文本的编码和表示。 它使您可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。 Swift 的 StringCharacter 类型是完全兼容 Unicode 标准的。
字符串字面量可以包含以下特殊字符:

  • 转义字符\0(空字符)、\\(反斜线)、\t(水平制表符)、\n(换行符)、\r(回车符)、\"(双引号)、\'(单引号)。
  • Unicode 标量,写成\u{n}(u为小写),其中n为任意一到八位十六进制数且可用的 Unicode 位码。

计算字符数量

  • 如果想要获得一个字符串中Character值的数量,可以使用字符串的characters属性的count属性。
  • 注意在 Swift 中,使用可拓展的字符群集作为Character值来连接或改变字符串时,并不一定会更改字符串的字符数量。
  • 注意: 可扩展的字符群集可以组成一个或者多个 Unicode 标量。这意味着不同的字符以及相同字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间数量。因此在没有获取字符串的可扩展的字符群的范围时候,就不能计算出字符串的字符数量。如果您正在处理一个长字符串,需要注意characters属性必须遍历全部的 Unicode 标量,来确定字符串的字符数量。
  • 另外需要注意的是通过characters属性返回的字符数量并不总是与包含相同字符的NSString的length属性相同。NSString的length属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集。作为佐证,当一个NSString的length属性被一个Swift的String值访问时,实际上是调用了utf16Count。

访问和修改字符串

  • 每一个String值都有一个关联的索引(index)类型,String.Index,它对应着字符串中的每一个Character的位置。
  • 使用startIndex属性可以获取一个String的第一个Character的索引。使用endIndex属性可以获取最后一个Character的后一个位置的索引。因此,endIndex属性不能作为一个字符串的有效下标。如果String是空串,startIndex和endIndex是相等的。
  • 通过调用String.Index的predecessor()方法,可以立即得到前面一个索引,调用successor()方法可以立即得到后面一个索引。任何一个String的索引都可以通过锁链作用的这些方法来获取另一个索引,也可以调用advancedBy(_:)方法来获取。但如果尝试获取出界的字符串索引,就会抛出一个运行时错误。

插入和删除 (Inserting and Removing)

  • 调用insert(_:atIndex:)方法可以在一个字符串的指定索引插入一个字符。
  • 调用insertContentsOf(_:at:)方法可以在一个字符串的指定索引插入一个字符串。
  • 调用removeAtIndex(_:)方法可以在一个字符串的指定索引删除一个字符。
  • 调用removeRange(_:)方法可以在一个字符串的指定索引删除一个子字符串。

比较字符串

  • Swift 提供了三种方式来比较文本值:字符串字符相等、前缀相等和后缀相等。
  • 通过调用字符串的hasPrefix(:)/hasSuffix(:)方法来检查字符串是否拥有特定前缀/后缀,两个方法均接收一个String类型的参数,并返回一个布尔值。

字符串的 Unicode 表示形式

当一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种编码格式编码。每一个字符串中的小块编码都被称为代码单元。这些包括 UTF-8 编码格式(编码字符串为8位的代码单元), UTF-16 编码格式(编码字符串位16位的代码单元),以及 UTF-32 编码格式(编码字符串32位的代码单元)。
Swift 提供了几种不同的方式来访问字符串的 Unicode 表示形式。 您可以利用for-in来对字符串进行遍历,从而以 Unicode 可扩展的字符群集的方式访问每一个Character值。 该过程在 使用字符 中进行了描述。

  • UTF-8 代码单元集合 (利用字符串的utf8属性进行访问)
  • UTF-16 代码单元集合 (利用字符串的utf16属性进行访问)
  • 21位的 Unicode 标量值集合,也就是字符串的 UTF-32 编码格式 (利用字符串的unicodeScalars属性进行访问)

集合类型 (Collection Types)

集合的可变性(Mutability of Collections)

  • Swift 语言提供Arrays、Sets和Dictionaries三种基本的集合类型用来存储集合数据。数组是有序数据的集。集合是无序无重复数据的集。字典是无序的键值对的集。
  • Swift 语言中的Arrays、Sets和Dictionaries中存储的数据值类型必须明确。这意味着我们不能把不正确的数据类型插入其中。同时这也说明我们完全可以对取回值的类型非常自信。
  • 如果创建一个Arrays、Sets或Dictionaries并且把它分配成一个变量,这个集合将会是可变的。这意味着我们可以在创建之后添加更多或移除已存在的数据项来改变这个集合的大小。如果我们把Arrays、Sets或Dictionaries分配成常量,那么它就是不可变的,它的大小不能被改变。
  • 在我们不需要改变集合大小的时候创建不可变集合是很好的习惯。如此 Swift 编译器可以优化我们创建的集合。

数组(Arrays)

  • 数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。
  • 可以使用数组的只读属性count来获取数组中的数据项数量。
  • 使用布尔值属性isEmpty作为检查count属性的值是否为 0 的捷径。
  • 也可以使用append(_:)方法在数组后面添加新的数据项。
  • 调用数组的insert(_:atIndex:)方法来在某个具体索引值之前添加数据项。
  • 类似的我们可以使用removeAtIndex(_:)方法来移除数组中的某一项。
  • 如果我们只想把数组中的最后一项移除,可以使用removeLast()方法而不是removeAtIndex(_:)方法来避免我们需要获取数组的count属性。

集合(Sets)

  • 集合(Set)用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。
  • 一个类型为了存储在集合中,该类型必须是可哈希化的–也就是说,该类型必须提供一个方法来计算它的哈希值。一个哈希值是Int类型的,相等的对象哈希值必须相同,比如a==b,因此必须a.hashValue == b.hashValue。
  • 使用intersect(_:)方法根据两个集合中都包含的值创建的一个新的集合。
  • 使用exclusiveOr(_:)方法根据在一个集合中但不在两个集合中的值创建一个新的集合。
  • 使用union(_:)方法根据两个集合的值创建一个新的集合。
  • 使用subtract(_:)方法根据不在该集合中的值创建一个新的集合。

字典(Dictionaries)

控制流(Control Flow)

For 循环

  • for-in循环对一个集合里面的每个元素执行一系列语句。
  • for 循环,用来重复执行一系列语句直到达成特定条件达成,一般通过在每次循环完成后增加计数器的值来实现。

for initialization; condition; increment { statements }

  1. 循环首次启动时,初始化表达式( initialization expression )被调用一次,用来初始化循环所需的所有常量和变量。
  2. 条件表达式(condition expression)被调用,如果表达式调用结果为false,循环结束,继续执行for循环关闭大括号(})之后的代码。如果表达式调用结果为true,则会执行大括号内部的代码。
  3. 执行所有语句之后,执行递增表达式(increment expression)。通常会增加或减少计数器的值,或者根据语句输出来修改某一个初始化的变量。当递增表达式运行完成后,重复执行第 2 步,条件表达式会再次执行。

While 循环

  • while循环,每次在循环开始时计算条件是否符合;
  • repeat-while循环,每次在循环结束时计算条件是否符合。

条件语句

控制转移语句(Control Transfer Statements)

提前退出

检测API可用性

函数

函数是用来完成特定任务的独立的代码块。你给一个函数起一个合适的名字,用来标识函数做什么,并且当函数需要执行的时候,这个名字会被“调用”。

Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以既当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。

在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。

函数定义与调用(Defining and Calling Functions)

函数参数与返回值(Function Parameters and Return Values)

函数参数名称(Function Parameter Names)

函数类型(Function Types)

  • 函数类型有什么具体的应用场景?

函数嵌套(Nested Functions)

闭包(Closures)


本页最后更新时间:2015-10-27 Tue 21:16.
小过的布拉格 - Copyright©2013-2017 - @xiaoguo - Powered by Emacs 26.1 (Org mode 9.1.1)
行路难,行路难, 多歧路,今安在。长风破浪会有时,直挂云帆济沧海。