控制流
repeat语句
repeat-while语句的功能和语法和do-while循环语句的是一样的,仅仅是把do改成了repeat,但repeat的好处在于能够立即从语句块的顶部看出这是一个循环,换成是从前的do,当语句块中的代码非常多且冗长时,通过一个do我们并不能判断这是一个do-while还是do-catch语句。
enum fruits {
case Apple, Banana, Cherry, Date, Emblic
}
let fav = Date
print(fav)
//输出fruits.Date
现在输出枚举类型时能同时显示枚举名和其实例名。
现在枚举类型可以表达不同值类型的关联,可以把不同类型的两个值存储在一个地方了。
enum Either<T1, T2>{
case First(T1)
case Second(T2)
}
枚举类型还增加了一个indirect关键词,使得枚举类型可以实现递归。
enum Tree<T>{
case Leaf<T>
indirect case Node<Tree,Tree>
}
option sets选项集合
在swift2.0以前,option set用来表示一个布尔类型的集合,如下的语在Cocoa中广泛地使用,但这只是C语言的一种复用。Swift2.0通过建立一个OptonSetType协议来代替这种句法,现在一个可选集合可以是任意遵守OptionSetType协议的集合或者结构体。这样一来就不需要再依赖按位运算符,也不用把一个空的可选集合定义为nil值。
//swift1
viewAnimationOptions = .Repeat | .CurveEaseIn | .TransitionCurlUp
viewAnimationOptions = nil
if viewAnimationOptions & .TransitionCurlUp != nil {..
//swift2
viewAnimationOptions = [.Repeat, .CurveEaseIn, .TransitionCurlUp]
viewAnimationOptions = [ ]
if viewAnimationOptions.contains(.TransitionCurlUp) {..
看另外一个实例struct MyFontStyle : OptionSetType {
let rawValue :Int
static let Bold = MyFontStyle(raw value: 1)
static let Italic = MyFontStyle(raw value: 2)
static let Undeline = MyFontStyle(raw value: 4)
static let Strikethrough = MyFontStyle(raw value: 8)
}
myFont.style = []
myFont.style = [.Underline]
myFont.style = [.Bold, .Italic]
if myFont.style.contains(.StrikeThrough) {…
方法和函数
Swift中,函数(function)指的是全局函数,方法(method)指的是在特定的类型如类,结构体中定义的函数。也就是说,函数可以直接通过函数名调用,而方法在调用时必须带上所归属的类或结构体的名字。在Swift2.0以前,方法和函数的定义和调用不同。Swift2.0做出的改变使得函数和方法的定义统一了。
//Swift 1
func save(name: String, encrypt: Bool) { ... }
class Widget {
func save(name: String, encrypt: Bool) { ... }
save("thing", false)
widget.save("thing", encrypt: false)
//Swift 2
func save(name: String, encrypt: Bool) { ... }
class Widget {
func save(name: String, encrypt: Bool) { ... }
save("thing", encrypt: false)
widget.save("thing", encrypt: false)
如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。
此外,在Swift2.0中,
func save(_ name: String, encrypt encrypt: Bool)
func save(name name: String, _ <span style="font-family: Arial, Helvetica, sans-serif;"> encrypt: Bool)</span>
func save(name: String, _ encrypt: Bool)
一般情况下,第一个参数到外部参数名可以省略不写,如果你不想为第二个及后续的参数设置外部参数名,用一个下划线_代替一个明确的参数名。
以上三种写法是一样的。
模式匹配
guard语句
我们知道,if语句通过判断其后面的条件语句是否为真来决定是否执行 {...} 后的内容,if语句的坏处是,当有多个if语句嵌套在一起时,程序往往变得难以理解,在Swift2.0中,新增的guard语句可以自然地解决这个问题,当guard后的判断条件为false时才能执行后面的内容,这样一来,判断语句可以从多个嵌套中解放,用只允许单一语句块的guard代替。
Swift2.0中新增的guard else语法允许提前退出,当name常量赋值失败时,guard语句确保程序可以安全退出。
guard let name = person["name"] else {
return
}
println(name)
switch语句
当switch语句中只有一个case选项时,句法往往会显得很厚重,现在可以通过if语句代替厚重的one-case switch。
// Swift 1
switch bar() {
case .MyEnumCase(let value) where value != 42: {...}
default: break
}
// Swift 2
if case .MyEnumCase(let value) = bar() where value != 42 {...}
for-in语句
//Swift 1
or value in mySequence {
if value != "" {
doThing(value)
}
}
//Swift 2
for value in mySequence where value != "" {
doThing(value)
}
for-in语句现在也支持在遍历的过程中通过where关键词增加条件来达到筛选的目的。
API可用性检查
API可用性(API availability)旨在让程序员确定在给定系统版本中部分API函数的可用性。Swift 2.0中,编译器可以通过if #available(...)关键句确保在一个给定的最小部署目标下什么API可用,什么不可以。这使得程序员可以避免在旧的平台上调用新函数时触发编译错误。#available()函数来检查API函数的可用性
if #avaiable(iOS9, OS X 10.10, *) {
//Avaiable on iOS9 and OS X 10.10
}else{
//Early version
}
协议扩展
协议定义不同的属性和方法,供类、结构体、枚举遵循和实现。现在不仅可以做到如上的所有定义,还可以像扩展结构体和类一样,对属性和方法进行扩展。假如你在一个数组类中扩展了如下的功能:
extension Array {
func countIf(match: Element ->maBtocohl:)T.-G>enIenrtat{or.Element -> Bool) -> Int {
var n = 0
for value in self {
if match(value) { n++ }
}
return n
}
当countIf需要在其他类中使用时,有两种方法可以做到,一是将countIf方法的定义通过复制粘贴的方式扩散到要被使用的地方,二是将countIf定义为全局函数。但以上的两种方法都不见得好用,前者中Array的扩展难以解读,后者使得countIf不再是一个方法,也不再是一个类的扩展。为了解决这个问题,Swift2.0 可以在协议中定义方法,使得这个方法可以被所有遵循此协议的类型继承。
extension CollectionType {
func countIf(match: Element -> Bool) -> Int {
var n = 0
for value in self {
if match(value) { n++ }
}
return n
}
}
错误处理
throw语句
在Swift2.0中,可以在方法和函数中通过throw来抛出错误。
func checkResourceIsReachable() throws {
...
}
do-catch语句
所有有可能出现编译或运行错误的函数在被调用时都必须用到关键词try,当调用一个这样的函数,我们就可以在出错前通过do-catch语句来避免错误的发生。
func preflight() {
do {
try url.checkResourceIsReachable()
resetState()
return true
} catch {
return false
}
}
当然,你也可以跳过这一步骤直接允许错误在调用的时候被传送。
func preflight() throws {
try url.checkResourceIsReachable()
resetState()
}
do-catch语句支持模式匹配,所以你也可以这样写。
func preflight() {
do {
try url.checkResourceIsReachable()
resetState()
return true
} catch NSURLError.FileDoesNotExist {
return true
} catch let error {
return false
}
}
ErrorType枚举类型
Swift2.0中自带了一个ErrorType的枚举类型,程序员可以自己定义一个包含所有特点错误类型的枚举值。
enum ParseError: ErrorType {
case MissingAttribute(message: String)
}
defer语句
Swift 2.0提供了defer关键字,让我们可以实现和Java中的finally语句同样的效果。也就是说,不管前面的代码执行得到什么样的结果,在当前的代码域退出之前,defer语句块中的代码总能被执行。
struct ATM {
var log = ""
mutating func dispenseFunds(amount: Float, inout account: Account) throws{
defer {
log += "Card for \(account.name) has been returned to customer.\n"
ejectCard()
}
log += "====================\n"
log += "Attempted to dispense \(amount) from \(account.name)\n"
guard account.locked == false else {
log += "Account Locked\n"
throw ATMError.AccountLocked
}
guard account.balance >= amount else {
log += "Insufficient Funds\n"
throw ATMError.InsufficientFunds
}
account.balance -= amount
log += "Dispensed \(amount) from \(account.name). Remaining balance: \(account.balance)\n"
}
func ejectCard() {
// physically eject card
}
}
var atm = ATM()
var billsAccount = Account(name: "Bill's Account", balance: 500.00, locked: true)
do {
try atm.dispenseFunds(200.00, account: &billsAccount)
} catch let error {
print(error)
}
var margretsAccount = Account(name: "Margret's Account", balance: 50.00, locked: false)
do {
try atm.dispenseFunds(80.00, account: &margretsAccount)
} catch let error {
print(error)
}
如上定义一个ATM结构体,用于实现ATM机的功能。定义了Bill和Margret两个账户。程序的运行结果表示,不管用户是否取钱成功,最终银行卡都会退还给他们,而这个功能就是通过ATM结构体中的defer语句块实现的。