swift 3.0 第3-6章中文

3 字符及字符串

字符串即一串字符, 比如”hello world”. Swift 中的字符串使用 String 类型表示.

Swift 中的 StringCharacter都是 Unicode 兼容的.

而且 Swift 中的字符串可以用 + 进行连接. 而且字符串的可变性直接由字符串是常量还是变量来控制, 不需要像 Foundation 中的字符串还需要使用 Mutable.

NOTE

Swift 中的字符串和 Foundation框架中的 NSString 进行了桥接. 即假如你现在是在使用Foundation框架, 那 NSString 中的所有 API 都可以使用到 String 上(需要进行类型转换后使用). 在所有需要使用 NSString 的 API 都可以使用 String 代替.

更多信息详见: Using Swift with Cocoa and Objective-C(Swift 3).

3.1 字符串常量

字符串常量用 "" 包含, 如下所示:

let someString = "Some string literal value."

3.2 初始化空字符串

有两种方式:

var emptyString = ""    //使用字符串常量初始化
var anotherEmptyString = String()   //使用初始化方法初始化

字符串的判空方法也非常简单:

if emptyString.isEmpty() {
  ...
}

3.3 字符串的可变性

可变字符串使用 var 定义, 不可变字符串使用 let 定义:

var variableString = "Horse"        //字符串变量/可变字符串
variableString += "and carriage"

let constantString = "Highlander"   //字符串常量/不可变字符串

NOTE

这里的方式和 Cocoa 中的字符串不同, Cocoa 中可变字符串为 NSMutableString ,不可变字符串为 NSString.

3.4 字符串是值类型的

Swift 中的 String 为值类型的, 意味着如果要将这个字符串用作赋值操作或参数传递时, 字符串会被复制. 比如赋值时, 本来的字符串会被复制, 然后被赋值变量获得的是复制出来的那个字符串. 字符串作为参数进行传递时也是如此.

Swift 中的这种对值类型量的默认复制行为可以保证当向函数或方法中传入一个 String 时, 该字符串都是函数或方法拥有的, 即便原字符串被销毁, 参数也不会受到影响.

实际上在底层, 由编译器负责决定字符串是否需要进行复制, 只有当需要时才会复制. 所以性能不会受到复制行为太大的影响.

3.5 字符

可以使用 for-in 语句来遍历 String 内的每一个字符:

for character in "hello world".characters {
  print(character)
}

另外, 可以自己创建单个字符, 此时该字符类型为 Character:

let exclamationMark: Character = "!"

可以传入多个字符来构造 String:

let catCharacters: [Character] = ["C", "a", "t"]
let catString = String(catCharacters)
print(catString)    //打印 cat

3.6 字符串连接

字符串可以进行相加(或连接), 方法是使用 +:

let string1 = "hello"
let string2 = " there"
let welcome = string1 + string2

也可以在字符串尾部追加字符:

let exlamationMark: Character = "!"
welcome.append(exlamationMark)

3.7 字符串内插

内插是一种常用的构造字符串方式:

let multiplier = 3
let message = "\(multiplier) times 2.5" //message为 "3 times 2.5"

即使用 \() 控制符来在字符串中内插变量值.

NOTE

在字符串中内插的值中不能包含 \, 或是回车或换行.

3.8 Unicode

Unicode 是一种用于文本的编解码以及处理表示的国际标准, 支持世界上绝大多数的书写系统.

Swift 中的 String 以及 Character 类型完全兼容 Unicode 标准.

3.8.1 Unicode 原子类型

Swift 中的 String 类型在底层是构建在 Unicode 数值量上的. 一个 Unicode 数值量是一个21 bit 的数字, 表示一个字符或修饰符, 比如 U+0061 表示的就是拉丁字母小写的”a”.

NOTE

一个 Unicode 数值量介于 U+0000 到 U+D7FF , 以及 U+E000 到 U+10FFF 之间. 不包括 Unicode 替代对所处的 U+D800 到 U+DFFF 区间.

但是要注意, 并非所有的21 bit Unicode 数值量都被分配给了字符, 有一些是未分配的保留值.

被分配了的 Unicode 数值量都有自己的名字, “a”的名称是 LATIN SMALL LETTER A.

3.8.2 字符串常量中的特殊字符

字符串常量中可以包含如下的特殊字符:

  • \0 (null) , \ \ (backslash), \t (horizontal tab), \n (line feed), \r (carriage return), \” (double quote), \’ (single quote)
  • 任意的 Unicode 数量值, 用 \u{n} 表达, n 是一个1到8位的十六进制数, 对应一个Unicode字符编码.

如下代码中展示如何包含这些特殊字符:

let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
let dollarSign = "\u{24}"   //$ 符号, 即 U+0024

3.8.3 扩展字符集

扩展字符集是一种灵活表示特殊字符的方式.

3.9 字符计数

调用字符串的 characters 属性的 count 方法进行计数:

let helloWorld = "hello world"
print(helloWorld.characters.count)

但需要注意的是, 有时在字符串中追加组合 Unicode字符不会影响字符串计数.

3.10 字符串的访问和修改

访问以及修改字符串可以调用 String 中的方法, 或者是直接通过下标操作符访问.

3.10.1 字符串下标

字符串中的每一个字符都有对应的下标. 但由于不同的字符需要不同的存储空间, 为了查看字符的位置, 需要从头到尾枚举这个字符串. 由于这个原因, Swift 中字符串无法由整数值定位字符.

使用 startIndex 定位第一个字符, 而 endIndex 指示的是字符串中最后一个字符的后面一个位置, 所以 endIndex 并不是有效的字符下标. 若字符串为空, 则 startIndexendIndex 相等.

使用 index(before:) 来访问某 index 的前驱, 使用 index(after:) 访问某 index 的后继.

另外如果要访问某 index 之后某个偏移位置, 可以使用 index(_:offsetBy:):

let greeting = "Guten Tag!"
greeting[greeting.startIndex]       //开始位置: G
greeting[greeting.index(before: greeting.endIndex)]     //结束位置之前: !
greeting[greeting.index(after: greeting.startIndex)]    //开始位置之后: u

let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]     //开始位置后偏移7: a

需要注意的是, 如果下标访问时超过了字符串或字符的长度范围, 则会触发运行时错误.

另外, 如果想访问字符串中每一个字符, 如下方法也可以办到:

for index in greeting.characters.indices {  //访问字符串中的 indices 属性中每一个index.
    print(greeting[index], terminator: "")
}

下面的代码效果也是相同:

for character in greeting.characters {//直接枚举每个字符
    print(character, terminator: "")
}

NOTE

只要是接受 Indexable 协议的类型, 都可以使用 startIndex, endIndex, index(befor:) 等方法.

这里只看到 String, 其实还有 Array, Dictionary 以及 Set.

3.10.2 插入和删除

var welcome = "hello there"
welcome.insert("!", at: welcome.endIndex)
welcome.insert(contentsOf: "how are you".characters, at: welcome.endIndex)
welcome.remove(at: welcome.index(before: welcome.endIndex))
let range = welcome.index(welcome.endIndex, offsetBy: -6) ..< welcome.endIndex
welcome.removeSubrange(range)

不过需要注意的是, 插入和删除的都是字符.

3.11 字符串比较

Swift 中提供了三种文本间比较方式: 字符串及字符的判等, 前缀比较, 后缀比较.

3.11.1 字符和字符串的判等

使用 == 以及 != 来判断.

3.11.2 前缀和后缀比较

使用字符串的 hasPrefix(_:) 以及 hasSuffix(_:) 方法来比较, 这两个方法都接受一个 String 类型的参数并返回一个布尔值.

3.11.3 Unicode 编码表示的字符串

暂时略.

4 集合类型

Swift 中提供了三种集合类型, 即 Array, Set, Dictionary.

其中 Array是有序的, 有序这里指其中元素都至少拥有一个前驱或后继.

Set 以及 Dictionary 都是无序的, 且 Dictionary 是无序键值对集合, Set内的元素都是唯一的. 而且集合中存放的数据都是有确定类型的.

NOTE

Swift 中的 Array Set 以及 Dictionary 都是以泛型方式实现的.

4.1 集合的可变性

和字符串类似, 若将集合赋值给变量, 则其可变, 若赋值给常量, 则其不可变.

NOTE

若确定集合不会发生变化, 应尽量将其设置为不可变, 即常量. 这样可以方便之后理解代码含义, 并且有利于编译器优化代码.

4.2 数组

Array 为存放相同数据类型元素的有序表, 且相同元素可以在数组中多个不同位置重复出现.

NOTE

Swift 的 Array 已经和 Foundation 框架中的 NSArray 进行了桥接.

4.2.1 数组简便表示

Swift 中某数组内存放的总是相同数据类型的对象, 它的完整表示为: Array[ElementType].

而简便表示为: [ElementType].

实际编程中, 推荐使用简便表示形式来表示数组.

4.2.2 创建空数组

var someInts = [Int]()

若之前数组不空, 但之后置空该数组, 则该数组的类型仍然不变.

4.2.3 使用初值创建数组

Array 还提供了一种初始化方法:

var threeDoubles = Array(repeating: 0.0, count: 3)

上面代码指定数组长度为3, 每个元素均为0.

4.2.4 两数组相加创建新数组

可以直接使用 + 操作符将两个数组合并生成新数组:

var threeDoubles = Array(repeating: 0.0, count: 3)
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
//此时sixDoubles 为 0.0, 0.0, 0.0, 2.5, 2.5, 2.5

4.2.5 使用数组常量创建数组

使用如下方式来创建数组常量:

  • [value1, value2, value3]

比如创建一个字符串数组:

var shoppingList = ["egg", "milk"]

此时shoppingList数组的类型为: [String].

4.2.6 数组的访问和修改

可以利用数组的方法或属性来访问数组, 并且可以使用下标语法访问或修改数组.

  • 查看元素个数: count属性

  • 判空: isEmptytrue, 或 count 为 0

  • 在尾部追加元素: append(_:)

    另外还可以使用 += 在尾部追加元素或追加数组(即之前提到的 + 的效果)

  • 下标访问及修改(从零开始计):

    var firstItem = shoppingList[0]
    shoppingList[0] = "Six eggs"

    一个更方便的语法, 在下标中使用范围操作符修改数组:

    shoppingList[4...6] = ["Bananas", "Apples"]

    这个语法…

    但这种语法只能用于修改, 不能用于在尾部追加.

  • 插入元素: 调用 insert(_:at:) 方法.

  • 移除元素: 调用 remove(at:) 方法.

    这个方法移除指定下标位置元素, 并返回被删除元素.

  • 移除尾元素: removeLast().

NOTE

当尝试访问超过数组下标界限的下标时, 将触发运行时错误. 很多错误都是由于count引起的, 因为count值为元素总个数, 但是数组中最后一个元素的下标是count - 1, 而非count.

4.2.7 遍历数组

  1. 使用 for-in 循环来遍历数组, 此时可以获取数组的每个元素的值

  2. 若想同时获取元素值与元素下标, 则使用 enumberated() 方法配合 for-in 循环:

    let arr1 = Array(repeating: 1.1, count: 3)
    let arr2 = Array(repeating: 2.2, count: 3)
    let arr3 = arr1 + arr2
    for (index, value) in arr3.enumerated() {
    print("index: \(index).......item: \(value)")
    }

    打印结果如下:

    index: 0.......item: 1.1
    index: 1.......item: 1.1
    index: 2.......item: 1.1
    index: 3.......item: 2.2
    index: 4.......item: 2.2
    index: 5.......item: 2.2

5 流程控制

swift 中有 for-in 循环和 while 循环, 其中 while 循环有两种, 一种是纯 while, 另外一种是 repeat-while.

repeat {
...
} while condition

在swift中无需显式写switch语句的break.
满足多个条件可以像如下这样写:

let anotherCharacter: Character = "a"
switch anotherCharacter {
  case "a", "A":    //满足条件 a 或 A 都会跳入这个语句中来.
      print("The letter A")
  default:
      print("Not the letter A")
}
  ```
在Swift中还有如下方便的Switch写法:
```swift
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
var naturalCount: String
switch approximateCount {
case 0:
    naturalCount = "no"
case 1..<5:
    naturalCount = "a few"
case 5..<12:
    naturalCount = "several"
case 12..<100:
    naturalCount = "dozens of"
case 100..<1000:
    naturalCount = "hundreds of"
default:
    naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// Prints "There are dozens of moons orbiting Saturn."




<div class="se-preview-section-delimiter"></div>

上述为范围的匹配.

另外swift中 Switch 和 元组一起使用也十分方便:

let somePoint = (1, 1)  //一个 (Int, Int) 类型的元组
switch somePoint {
case (0, 0):
    print("(0, 0) is at the origin")
case (_, 0):  //这里的下划线表示任意值的匹配.
    print("(\(somePoint.0), 0) is on the x-axis")
case (0, _):
    print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
    print("(\(somePoint.0), \(somePoint.1)) is inside the box")
default:
    print("(\(somePoint.0), \(somePoint.1)) is outside of the box")
}
// Prints "(1, 1) is inside the box"




<div class="se-preview-section-delimiter"></div>

另外多个匹配项在Swift中也是允许的, 比如上面的点(0, 0), 它满足所有四个条件, 但Swift中对这样情况的处理是匹配第一个满足的条件.

5.1 值绑定

Swift 中的 Switch 还可以进行值绑定, 将绑定的值用在语句块中:

let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
    print("on the x-axis with an x value of \(x)")
case (0, let y):
    print("on the y-axis with a y value of \(y)")
case let (x, y):
    print("somewhere else at (\(x), \(y))")
}




<div class="se-preview-section-delimiter"></div>

这个例子中的Switch不含Default语句 ,在Swift中允许这样的Switch, 因为最后一个条件就包括了其他的全部可能.

5.2 Switch 中的 where 语句

在Swift中, Switch 还可以在条件中加入where:

let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
    print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}
// Prints "(1, -1) is on the line x == -y"




<div class="se-preview-section-delimiter"></div>

5.3 多个值在同一行

Switch 的case 可以允许多个值在同一行, 多个值使用的逻辑连接是 “或”:

let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
    print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
     "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
    print("\(someCharacter) is a consonant")
default:
    print("\(someCharacter) is not a vowel or a consonant")
}
// Prints "e is a vowel"




<div class="se-preview-section-delimiter"></div>

并且, 多个值也可以进行值绑定:

let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):
    print("On an axis, \(distance) from the origin")
default:
    print("Not on an axis")
}
// Prints "On an axis, 9 from the origin"




<div class="se-preview-section-delimiter"></div>

6 流程转移语句

  • continue: 终止当前一轮循环, 立即进入下一轮循环.
  • break: 用于跳出循环或Switch语句.
  • fallthrough: 用于Switch语句, 好让其拥有类似C的向下流的行为.
  • return: 返回语句
  • throw:

6.1 guard关键字

使用它就类似于if, 只是它的语句块是当条件为假时执行:

func greet(person: [String: String]) {
    guard let name = person["name"] else {
        return
    }

    print("Hello \(name)!")

    guard let location = person["location"] else {
        print("I hope the weather is nice near you.")
        return
    }

    print("I hope the weather is nice in \(location).")
}

greet(person: ["name": "John"])
// Prints "Hello John!"
// Prints "I hope the weather is nice near you."
greet(person: ["name": "Jane", "location": "Cupertino"])
// Prints "Hello Jane!"
// Prints "I hope the weather is nice in Cupertino."




<div class="se-preview-section-delimiter"></div>

若guard条件满足, 则直接向下执行, 否则会它的else语句块中执行.

6.2 API 可用性判断

在swift中内置了API的可用性判断, 这样可以避免误用API.

if #available(iOS 10, macOS 10.12, *) {
    // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
    // Fall back to earlier iOS and macOS APIs
}

上面的可用性检查语句 #available , 第一个参数指定 iOS平台的话, 是iOS10 以上版本, 第二个参数说明在macOS平台的话 ,必须是10.12版以上, 第三个参数 * , 表示其他任何平台.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值