Swift-控制流(Control Flow)

swift里面的控制流分为For-In 循环While 循环条件语句控制转移语句提前退出检测 API 可用性


For-in循环

相对于OC,Swift对for-in做出了加强,不仅仅能对数组遍历,还能对字符串和字典遍历,范围可以使用闭区间,item值可以用(_)进行忽略,还加入了stride(from:to:by:)stride(from:through:by:) 等新API

遍历字符串
let name = "Logan"
for char in name {
    print(char)
}
//L
//o
//g
//a
//n
复制代码
遍历数组
let names = ["zhangsan", "lisi", "wangwu"]
  for name in names {   
    print(name)
  }
// zhangsan 
// lisi
// wangwu
复制代码
遍历字典
  • 通过遍历字典来访问它的键值对。遍历时,字典的每项元素会已(key, value)元祖的形式返回
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
    print("\(animalName)s have \(legCount) legs")
}
// ants have 6 legs
// spiders have 8 legs
// cats have 4 legs
复制代码
区间遍历
for index in 1...5 {
     print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
复制代码
忽略变量遍历
  • 当不需要区间序列内的每一项值,可以用下划线(_)替代变量名来忽略这个值,如下:
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
    answer *= base
}
print("\(base) to the power of \(power) is \(answer)")
// 输出 "3 to the power of 10 is 59049"
复制代码
跨越遍历
  • 当只需要取被遍历集合中的部分数据是可以使用跨越遍历(自己取的名字- -),方法名为:stride(from:to:by:)stride(from:through:by:) 如下:
let minutes = 60
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
    // 每5分钟渲染一个刻度线(0, 5, 10, 15 ... 45, 50, 55)
}
复制代码
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
    // 每3小时渲染一个刻度线(3, 6, 9, 12)
}
复制代码

可以这么理解: to不包含最后一个值,through包含最后一个值

While循环

while循环类似OC的用法,一直运行到条件变成false。而swift提供两种循环形式:whilerepeat-while(每次在循环结束后检查条件是否符合,类似OC的do-while

while
  • 每次循环开始前检查条件是否符合(先判断再循环)如下:
var condition = 0
while condition < 3 {
    condition += 1
    print(condition)

}
// 1
// 2
// 3
复制代码
repeat-while
  • 每次在循环结束后检查条件是否符合(先循环然后再判断,类似OC的do-while)如下:
var condition = 3
repeat {
    condition += 1
    print(condition)
} while condition < 3
// 4
复制代码

条件语句

swift提供两种条件语句ifswitch

if条件语句
  • 先判断if后面的语句是否为true,然后执行相关代码。if 语句允许二选一执行,叫做 else 从句。也就是当条件为 false 时,执行 else语句如下:
temperatureInFahrenheit = 40
if temperatureInFahrenheit <= 32 {
    print("It's very cold. Consider wearing a scarf.")
} else {
    print("It's not that cold. Wear a t-shirt.")
}
// 输出 "It's not that cold. Wear a t-shirt."
复制代码
switch条件语句
  • switch语句会尝试把某个值与若干个模式进行匹配。根据第一个匹配成功的模式,switch语句会执行对应的代码。当有可能的情况较多时,通常switch语句替换if语句。每一个case都是代码执行的一条分支。switch语句会决定哪一条分支应该被执行。这个流程被称作根据给定的值切换(switching),switch语句必须完备,每一个可能的值都必须至少有一个case分支与之对应。当某些不能涵盖所有值得情况下,可以使用默认default分支来涵盖其它所有没有对应的值如下:
let someCharacter: Character = "z"
switch someCharacter {
case "a":
    print("The first letter of the alphabet")
case "z":
    print("The last letter of the alphabet")
default:
    print("Some other character")
}
// 输出 "The last letter of the alphabet"
复制代码
不存在隐式的贯穿
  • 与C和OC中的 switch 语句不同,在swift中,当匹配的case分支中的代码执行完毕后,程序会终止switch语句,而不会继续执行下一个case分支。也就是说,不需要在case分支中使用break。所以分支下必须要有执行语句,不然会编译错误如下:
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // 无效,这个分支下面没有语句
case "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// 这段代码会报编译错误
复制代码

为了让单个 case 同时匹配 aA,可以将这个两个值组合成一个复合匹配,并且用逗号分开如下:

let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
    print("The letter A")
default:
    print("Not the letter A")
}
// 输出 "The letter A
复制代码
switch区间分配
  • case分支的模式也可以是一个值的区间,使用区间匹配来输出任意数字对应的自然语言格式如下:
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let 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).")
// 输出 "There are dozens of moons orbiting Saturn."
复制代码
switch-元祖
  • 我们还可以使用元祖在同一个switch语句中测试多个值,元祖中的元素可以是值,也可以是区间。可以使用下划线(_)来匹配所有可能的值。使用一个(Int, Int)类型的元祖来分类下图中的点 (x,y) 如下:
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print("\(somePoint) is at the origin")
case (_, 0):
    print("\(somePoint) is on the x-axis")
case (0, _):
    print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
    print("\(somePoint) is inside the box")
default:
    print("\(somePoint) is outside of the box")
}
// 输出 "(1, 1) is inside the box"
复制代码

注: 不像OC,swift允许多个case匹配同一个值。实际上,如果 somePoint = (0, 0),则可以匹配上述的四个case。但是存在多个匹配,那么只会执行第一个被匹配到的case分支。考虑 *(0,0)*会首先匹配case(0,0),因而身下的能够匹配的分支都会被忽视掉。

绑定值
  • case分支允许将分配的值声明为临时常量或变量,并且在case分支内使用。这种行为被称为 绑定值,因为匹配的值在case分支体内,与临时的常量或变量绑定。如下:
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))")
}
// 输出 "on the x-axis with an x value of 2"
复制代码

注: 绑定值只作用于switch对应的case内。上面例子中的三个case都声明了常量xy的占位符,用于临时获取元祖anotherPoint的一个或两个值。第一个case *case(let x,0)*将匹配一个纵坐标为0的点,并吧这个点的横坐标赋值给临时常量x。类似的第二个case *case(0,let y)*将匹配一个横坐标为0的点,并把这个点的纵坐标赋值给临时常量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")
case let (x, y):
    print("(\(x), \(y)) is just some arbitrary point")
}
// 输出 "(1, -1) is on the line x == -y"
复制代码

注: 上述代码中的where实质相当于case分支中的额外判定条件生产的一个过滤器,当where语句的条件为true时,匹配到的case分支才会被执行。

控制转移语句

Swift中的控制转移语句共有下面五种: continuebreakfallthroughreturnthrow

Continue
  • continue 语句告诉循环体立即停止本次循环,重新开始下次循环。就好像再说“本次循环我已经执行完了”,但是并不会离开整个循环体。举例把一个小写字符串的元音字母和空格字符移除,生成一个含义模糊的短句如下:
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
for character in puzzleInput {
    switch character {
    case "a", "e", "i", "o", "u", " ":
        continue
    default:
        puzzleOutput.append(character)
    }
}
print(puzzleOutput)
// 输出 "grtmndsthnklk"
复制代码
Break
  • break语句会立刻结束整个控制流的执行,然后跳转到表示循环体结束的大括号后的第一行代码,不会再有本次循环的代码被执行,也不会有下次的循环产生。在switch中基本不用,可以在if循环语句中来提前结束,避免过多的遍历次数,举例如下:
let students = [["name":"xiaoming", "height":155], ["name":"xiaohua", "height":160], ["name":"xiaoli", "height":172]]
for student in students {
    if student["height"] as! Int >= 160 {
        print("There have students who are taller than 160")
        break
    }
}
// There have students who are taller than 160  *(只执行一次)
复制代码
fallthrough贯穿
  • 在Swift里,switch语句不会从上一个分支跳转到下一个分支中,只要匹配到相应的分支,就会去完成分支下的执行语句,整个switch代码块就会完成。加入fallthrough后就会继续执行下个case分支,举例如下:
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
    description += " a prime number, and also"
    fallthrough
default:
    description += " an integer."
}
print(description)
// 输出 "The number 5 is a prime number, and also an integer."
复制代码

注:fallthrough关键字不会检查下一个执行条件的case中的匹配条件。而是简单粗暴的继续连接到下个case分支的执行代码中。

提前退出

  • if语句一样,guard的执行取决于一个表达式的布尔值。我们可以使用guard语句来要求条件必须为真时,以执行guard代码块后的代码。不同于if语句,一个guard语句只有一个else从句,如果条件不为真则执行else从句中的代码。可以理解为guard实际是省略了if条件下执行代码块而只有else分支的关键字,但可读性更强。举例如下:
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(["name": "John"])
// 输出 "Hello John!"
// 输出 "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// 输出 "Hello Jane!"
// 输出 "I hope the weather is nice in Cupertino."
复制代码

注:else这个分支必须转移控制以退出 guard 语句出现的代码段。它可以用控制转移语句如 return,break,continue 或者 throw 做这件事,或者调用一个不返回的方法或函数,例如 fatalError()

检测 API 可用性

  • Swift 内置支持检查 API 可用性,这可以确保我们不会在当前部署机器上,不小心地使用了不可用的 API。 编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API,Swift 会在编译时报错。 我们在 ifguard 语句中使用 可用性条件(availability condition)去有条件的执行一段代码,来在运行时判断调用的 API 是否可用。编译器使用从可用性条件语句中获取的信息去验证,在这个代码块中调用的 API 是否可用。举例如下:
if #available(iOS 10, macOS 10.12, *) {
    // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API
} else {
    // 使用先前版本的 iOS 和 macOS 的 API
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值