Swift2 学习笔记 2 - 基础

比较简单的部分会用要点的形式列出来,比较复杂和语言本身特性的,会单独提出来介绍


  • 常量与变量
    • let 声明常量
    • var 声明变量
    • 一行可以声明多个,用逗号隔开:var x = 0.0, y = 0.0, z = 0.0
  • 类型标注(冒号和空格加上类型名称)
    • var welcomeMessage: String
    • 一行可以声明多个:var red, green, blue: Double
  • 输出常量和变量
    • 函数原型:print(_:separator:terminator:)
    • 通常来说 separatorterminator 有默认值可以忽略,如果想要自定义,可以这样:print(someValue, terminator: "") 这样就不会默认换行了
  • 字符串插值 string interpolation
    • 用反斜杠加一对括号
    • print("The value is \(someValue)")
  • 注释:///* */
  • 分号不强制要求,但是为了美观还是加上,或者如果一行写两个语句,就一定要分号
  • 整数:Swift 提供了 8, 16, 32, 64 的有符号和无符号整数类型
    • 如: UInt8, Int32 等
    • 整数范围: UInt8.min, UInt8.max,其他的类型类似
    • 32 位平台上,Int 和 Int32 长度相同
    • 64 位平台上,Int 和 Int64 长度相同
    • 统一使用 Int 可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推断
  • 浮点数
    • Double 64 位浮点数
    • Float 32 位浮点数
  • Swift 是一个类型安全的语言
  • Swift 也会尽可能通过类型推断来选择合适的类型
  • 数值型字面量
    • 十进制数:没有前缀
    • 二进制数:0b
    • 八进制数:0o
    • 十六进制数:0x
  • 类型转换
    • 整数和浮点数转换必须显式指定类型
  • 类型别名
    • typealias 关键字来定义,如 typealias AudioSample = UInt16
  • 布尔值:true 和 false
  • 元组
    • 圆括号包起来的变量:http404Error = (404, "Not Found")
    • 分解元素内容 let (statusCode, Message) = http404Error
    • 如果只需要用一部分,忽略的部分用下划线表示 let (justCode, _) = http404Error
    • 还可以通过下标来访问元组的中单个元素,下标从零开始:http404Error.0
    • 可以在定义元组的时候给元素命名,这样就可以通过名字来获取对应的值:let http200Status = (statusCode: 200, description: "OK")
    • 元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构
  • 运算符
    • 基本的就不提了,和其他语言差不多,这里就记录一些要点
    • ++ 前置的时候,先自增再返回
    • ++ 后置的时候,先返回再自增
    • === 恒等,!== 不恒等
    • 三目运算符 (condition ? statement1 : statement2)
      • 应该避免在一个组合语句中使用多个三目运算符
    • 空合运算 (Nil Coalescing Operator)
      • (a ?? b) 将对可选类型 a 进行空判断,如果 a 包含一个值就进行解封,否则就返回一个默认值 b。
      • 相当于下列代码的简短表示: a != nil ? a! : b
    • 区间运算符
      • 闭区间运算符 ( a…b ),包括 a 也包括 b
      • 半开区间运算符 ( a…<b ),包括 a 不包括 b
    • 逻辑运算
      • !a, a&&b, a||b
  • 字符串是值类型 Strings are value types,也就是说操作的时候会创建一个新的副本
    • 连接字符串和字符可以用 + 号,创建一个新的字符串
    • 字符串插值(String Interpolation),如 let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
    • Swift 的字符串完全兼容 Unicode
    • 计算字符数量,用字符串 characters 属性的 count 属性
    • let string = "Hello World" ; print(string.characters.count)
    • 通过字符串索引 startIndex, endIndex, startIndex.predecessor(), startIndex.succeessor() 来访问,或者也可以通过下标访问
    • 调用 insert(_:atIndex:) 方法可以在一个字符串的指定索引插入一个字符。
      • var welcome = "hello"; welcome.insert("!", atIndex:welcome.endIndex)
    • 删除字符或字符串 removeAtIndex(_:), removeRange(_:)
    • 比较字符串:==, !=, hasPrefix(_:) / hasSuffix(_:)
    • 字符串 Unicode 表示形式
  • For 循环
    • for initialization; condition; increment { ... }
    • for var variable in Collection { ... }
  • While 循环
    • while condition { ... }
    • repeat { ... } while condition
  • if 和 switch 可以看概览中的代码例子
  • 控制转移语句 Control Transfer Statements
    • continue
    • break
    • fallthrough 在分支中加上这个关键字就会落入到下一个分支中,不会检查匹配条件,类似于 C 语言 switch case 没加 break 的效果
    • return
    • throw
    • 还可以利用标签来明确是 break 出哪个循环,这个在多重循环逻辑中比较有用

可选类型

使用可选类型(optionals)来处理值可能缺失的情况,可选类型的值有两种可能:1.有值,等于 x。2.没有值,等于nil。举个例子

let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)

convertedNumber 被推测为 Int? 类型,表示可能包含 Int 值,也可能不包含值。

可以给可选变量赋值位 nil 来表示没有值,但 nil 不能用于非可选的常量和变量。如果声明一个可选常量或者变量但是没有赋值,会被自动设置为 nil

可以使用 if 语句和 nil 比较来判断一个可选值是否包含值。使用 ==!= 来执行比较。当确定可选类型确实包含值之后,可以在名字后面加一个感叹号来获取值,称为可选值的强制解析(forced unwrapping)。要注意的是使用 ! 来获取一个不存在的可选值会导致运行时错误。

if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}

可选绑定 optional binding

判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在 if 和 while 语句中,这样就可以同时完成赋值和判断两个任务,如

if let constantName = someOptional {
statements
}

也可以在 if 语句中包含多个可选绑定,然后用 where 子句做布尔值判断,如

if let firstNumber = Int("4"), secondeNumber = Int("42") where firstNumber < secondNumber {
print("\(firstNumber) < \(secondNumber)")
}
// print "4 < 42"

错误处理 error handling

一个函数可以通过在声明中添加 throws 关键词来抛出错误消息。当你的函数能抛出错误消息时,应该在表达式中前置 try 关键词

func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch Error.OutOfCleanDishes {
washDishes()
} catch Error.MissingIngredients(let ingredients){
byGroceries(ingredients)
}

断言

在运行时判断一个逻辑条件是否为 true。全局 assert(_:_file:line:) 函数来写一个断言。

let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// 因为 age < 0,所以断言会触发

适用情景

  • 整数类型的下标索引被传入一个自定义下标脚本实现,但是下标索引值可能太小或者太大
  • 需要给函数传入一个值,但是非法的值可能导致函数不能正常运行
  • 一个可选值现在是 nil,但是后面的代码运行需要一个非 nil 值。

集合类型 (Collection Types)

Swift 语言提供 Arrays, Sets 和 Dictionaries 三种基本集合类型,存储的数据必须明确,不能把不正确的数据类型插入其中。

在我们不需要改变集合大小的时候创建不可变集合是很好的习惯。这样 Swift 编译器可以优化我们创建的集合

数组 Arrays

会被桥接到 Foundation 中的 NSArray 类。应该遵循像 Array<Element> 这样的形式,其中 Element 是这个数组唯一允许存在的数据类型。也可以用 [Element] 这样的简单语法。

// 创建一个空数组
var someInts = [Int]()
// 如果代码上下文中已经提供了类型信息,可以使用一对空方括号来创建
someInts.append(3)
someInts = []
// 带有默认值的数组
var threeDoubles = [Double](count: 3, repeatedValue: 0.0)
// 两个数组相加创建一个数组
var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5)
var sixDoubles = threeDoubles + anotherThreeDoubles
// 用字面量构造数组
var shoppingList: [String] = ["Eggs", "Milk"]
// 可以使用数组中的只读属性 count 来获取数组中的数据项数量
print("The shopping list contains \(shoppingList.count) items.")
// 使用布尔值属性 isEmpty 作为检察 count 属性的值是否为 0 的捷径
if shoppingList.isEmpty {
print("The shoppinglist is empty.")
}
// 使用 append(_:) 方法在数组后面添加数据项
shoppingList.append("Flour")
// 也可以直接用 += 来进行添加
shoppingList += ["Baking Powder"]
// 用下标来改变数据
shoppingList[0] = "Six eggs"
// 或者范围批量替换
shoppingList[4...6] = ["Bananas", "Apples"]
// 插入数据
shoppingList.insert("Maple Syrup", atIndex: 0)
// 删除数据
let mapleSyrup = shoppingList.removeAtIndex(0)
let apples = shoppingList.removeLast()
// 用 for-in 循环来遍历数组
for item in shopppingList {
print(item)
}
// 用 `enumerate()` 方法来同时获取索引值和数据值
for (index, value) in shoppingList.enumerate(){
print("Item \(String(index + 1)): \(Value)")
}

集合 Sets

每个元素只出现一次,元素顺序不重要,会被桥接到 Foundation 中的 NSSet 类。存在集合中的类型必须可哈希化。集合的语法是 Set<Element>,但集合没有等价的简化形式

// 创建空集合
var letters = Set<Character>()
// 如果上下文提供了类型信息,创建空集合时可以简化
letters.insert("a")
letters = [] // 重新设为空,类型为 Set<Character>
// 用字面量声明集合
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// 因为用了字面量,其实类型的声明是可以省略的,上面的一句可以写为
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
// 用 count 获取元素数量
print ("I have \(favoriteGenres.count) favorite music genres.")
// 用 isEmpty 来看集合是否为空
if favoriteGenres.isEmpty {
print("As far as music goes, I'm not picky.")
}
// insert(_:) 添加新元素
favoriteGenres.insert("Jazz")
// remove(_:) 删除元素,会返回被删除的值,如果不包含则返回 nil
if let removedGenre = favoriteGenres.remove("Rock"){
print ("\(removedGenre)? I'm over it.")
}
// contains(_:) 检查是否包含一个特定的值
if favoriteGenres.contains("Funk") {
print ("I get up on the good foot")
}
// 遍历集合,用 for-in,用 sort() 方法可以返回一个有序集合
for genre in favoriteGenres.sort() {
print("\(genre)")
}

其他的一些集合操作

  • intersect(_:) 根据两个集合中都包含的值创建一个新的集合
  • exclusiveOr(_:) 在一个集合中但不在另一个集合中的值创建一个新的集合
  • union(_:) 两个集合的并集
  • subtract(_:) 两个集合的差集
  • == 判断集合相等
  • isSubsetOf(_:) 判断子集
  • isSupersetOf(_:) 判断超集
  • isStrictSubsetOf(_:) 判断严格子集
  • isDisjointWith(_:) 判断两个集合是否不含有相同的值

字典 Dictionary

键值对,被桥接倒 Foundation 的 NSDictionary,语法为 Dictionary<Key, Value>。作为 key 的必须是 Hashable 的,可以用 [Key: Value] 这样的快捷形式去创建一个字典

// 创建空字典
var namesOfIntegers = [Int: String]()
// 如果上下文提供了信息,可以简化
namesOfIntegers[16] = "sixteen"
namesOfIntegers = [:] // 设置为空字典
// 用字面量创建字典
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// 获取字典中元素的数量
print("The dictionary of airports contains \(airports.count) items.")
// 检查是否为空
if airports.isEmpty {
print("The airports dictionary is empty.")
}
// 下标添加新数据,如果已有对应的 key,会覆盖更新
// 用 updateValue(_:forKey:) 方法会返回更新前的值,可选类型,如果没有 key 的话会是 nil
airports["LHR"] = "London"
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB"){
print("The Old value for DUB was \(oldValue)")
}
// 用下标给某个 key 赋值为 nil 可以删除这个元素
// 也可以用 removeValueForKey(_:),方法会返回更新前的值,可选类型,如果没有 key 的话会是 nil
airports["APL"] = nil
// 用 for-in 来遍历字典,会以 (key, value) 元组形式返回
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
// 也可以单独用 keys 或者 values 属性来遍历,如果需要有序,可以用 sort() 方法
for airportCode in airports.keys {...}
for airportName in airports.values {...}

Switch 语句高级用法

switch 语句会尝试把某个值与若干个 pattern 进行匹配。每个 case 之间不需要用 break

比较常见的用法是

switch some value to consider {
case value 1:
respond to value 1
case value 2, value 3:
respond to value 2 or 3
default:
otherwise
}

区间匹配

因为是匹配一个 pattern,所以也可以利用区间,如下

let approximateCount = 62
switch approximateCount {
case 0:
print("no")
case 1..<5:
print("a few")
case 5..<12:
print("several")
default:
print("many")
}

元组

可以使用元组来测试多个值。用下划线来匹配所有可能的值

let somePoint (1, 1)
switch somePoint {
case (0, 0):
print("origin")
case (_, 0):
print("x-axis")
case (0, _):
print("y-zxis")
default:
print("else")
}

值绑定 Value Bindings

允许将匹配的值帮动刀一个临时的常量或变量上,就可以在 case 分支里引用

let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("x-axis with value \(x)")
case (0, let y):
print("y-axis with value \(y)")
case let (x, y):
print("else x:\(x) y:\(y)")
}

where

case 分支模式可以使用 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")
}

Guard 语句

要求条件必须为真才执行之后的代码,而且一定要带有一个 else 分句,如果条件不为真则执行 else 分句中的代码

guard let name = person["name"] else {
print("no name")
}

检测 API 的可用性

最后一个参数 * 是必须的,用于处理未来的潜在平台,例如:

if #available(iOS 9, OSX 10.10, *){
//... new api
} else {
//... old api
}
捧个钱场?