1、字符
在Objective-C中,字符是放在单引号('a')之间的。但是,在Swift中不能用这种方式表示。Swift中无论是字符还是字符串,都必须使用双引号("a"和"abc"):
let c: Character = 'a' // 编译错误
// 字符类型也需要放在双引号之间
let d: Character = "d" // 正确的写法
let e: Character = "ef" // 编译错误,字符类型的赋值只能有一个字符
// 字符串类型放在双引号之间
let str: String = "LeBron James"
另外,如果想声明一个字符类型,不能使用类型推断,必须明确指明它是Character,否则编译器会自动将其推断为String类型。也就是说,下面这种写法,编译器会把它当成String类型:
let a = "a" // 编译器推断其为字符串类型
2、字符串
在Foundation框架中有两种字符串类型,分别是Swift中的String类型,以及Objective-C中的NSString类型。String是结构体,属于值类型,而NSString是一个类,它是引用类型,在使用的时候要格外注意。
在Swift中,字符串的拼接,除了可以使用+、+=和append()方法之外,其实还可以使用()进行操作:
let num = 10
let result = "\(num)加\(3.14)等于\(Int(3.14) + num)"
print(result) // 13
\()被称为字符串插值,其功能非常强大,几乎可以将任何数据类型拼接起来,尤其是在通过print()函数进行打印的时候,用起来非常的方便。
字符串和整型一样,是可以进行相等和大小比较的,比较的依据是Unicode字符编码的值。比如说:
let kingJames = "LeBron James"
let flash3 = "Dwyane Wade"
// 进行大小比较
if kingJames > flash3 {
print("谁大谁尴尬!")
} else {
print("比较的是字符串的Unicode编码值")
}
在Swift中,字符类型(Character)和字符串类型(String)都是值类型,只能用==或者!==比较是否相等;而NSString字符串是引用类型,需要使用===或者!==进行比较。
3、switch语句
在Swift中,switch语句的条件表达式可以是整型、浮点型、字符(串)、和元组等类型,并且判断语句case后面的值可以是一个,也可以是多个,甚至还可以是连续的范围:
// 1.switch的基本用法
// switch后面的小括号可以省略;
// switch后面的break也可以省略,系统会帮你添加)
let sex = 0 // sex为0表示男性,sex为1表示女性
switch sex {
case 0 :
print("性别为男性") // break可以省略,系统会默认帮你添加
fallthrough // 如果希望在switch中的case后面产生穿透,只需添加关键字fallthrough
case 1 :
print("性别为女性")
default:
print("亚文化性别")
}
// 2.case后面可以判断多个条件,多个条件以逗号进行分割。
let asian = 1 // 0表示中国人,1表示韩国人,2表示日本人
switch asian {
case 0, 1, 2 : // 多个判断条件以逗号分开
print("亚洲人!")
case 3 :
print("非洲人!")
default :
print("其它洲人")
}
// 3.switch中可以判断浮点型(OC中不能判断浮点型)
let pi = 3.141
switch pi {
case 1.414 :
print("根号2")
case 1.732:
print("根号3")
case 3.141:
print("圆周率")
default:
print("其它什么")
}
// 4.switch中可以判断字符串儿
let x = 3
let y = 7
let operation = "+" // 字符串儿
var z = 0
switch operation {
case "+":
z = x + y
case "-":
z = x - y
case "*":
z = x * y
case "/":
z = x / y
default:
print("非法操作符!")
}
// 5.switch可以判断区间(开区间:0..<10,表示0~9;闭区间:0...10,表示0~10)
let child = 0
switch child {
case 0...17:
print("未成年")
case 18..<44:
print("青年")
case 44..<60:
print("中年")
default:
print("老年")
}
在switch中不用显式的添加break语句,分支执行完毕就会自动跳出switch语句。如果希望人为增加穿透效果,需要在执行语句后面添加关键字fallthrough。
4、guard语句
guard语句是Swift 2之后才出现的关键字,它其实是if-else语句的变种,设计的目的是用来取代if嵌套,让代码变得更容易阅读。guard语句的基本格式为:
guard 条件表达式 else {
跳转语句 // 比如说return、break、continue和throw
}
语句组
当条件表达式为true时,会跳过else后面花括号中的跳转语句,直接执行后面的语句组;当条件表达式为false时,才会执行else后面花括号中的跳转语句:
let age = 16
// 定义一个函数,使用常规的if-else语句来执行
func getMarried(age : Int) {
// 判断一下是否到了法定结婚年龄
if age >= 22 {
print("可以结婚。")
} else {
print("未到法定结婚年龄!")
}
}
// 调用函数
getMarried(age: age)
/*
* 说明:如果只有一层if-else语句,不使用guard阅读性要好一些;
* 但是,如果有多层if else嵌套,使用guard的阅读性要好很多
*/
// 再定义一个函数,演示guard的使用
let myAge = 16
func drinkWine(age : Int) {
// 如果条件不成立,执行else后面花括号中的语句
guard myAge >= 18 else { // 条件为false
// 条件为false,会执行这里面的语句
print("不能喝酒!")
return
}
// 条件为true,就会跳过上面整个guard语句块,继续执行它下面的语句
print("可以喝酒。")
}
// 调用drinkWine函数
drinkWine(age: myAge)
guard语句或许没有if嵌套语句简洁,但是它能保证代码具有良好的阅读性。以常见的程序员招聘广告为例,我们来比较一下if嵌套语句和guard语句:
// 年龄
let age = 22
// 拥有本科学历
let bachelorDegree: Bool = true
// 拥有3年编程经验
let experience = 3
// if嵌套使用
func Employ() {
// 如果年满18周岁
if age > 18 {
// 如果拥有本科学历
if bachelorDegree {
// 如果拥有两年以上编程经验
if experience > 2 {
print("条件符合,可以录用")
}
}
}
}
Employ()
// 使用guard语句
func Hiring() {
// 如果年满18周岁,程序才会继续往下走
guard age > 18 else {
print("年龄未满18周岁")
return
}
// 如果拥有本科学历,程序才会接着往下走
guard bachelorDegree else {
print("未取得本科学士学位")
return
}
// 至少拥有两年以上编程经验,程序才会再次往下走
guard experience > 2 else {
print("编程经验不足")
return
}
// 如果程序能走到这里,说明上面的条件都满足
print("条件满足,可以录用")
}
Hiring()
guard语句在实际编程中用得非常多。就以我之前写得笔记《项目基本架构的搭建》为例,根据一个键去字典中取出对应的值,并不一定能取到,所以需要进行安全校验。只有从字典中取出了目标值,程序才需要接着往下走:
// 添加子控制器
fileprivate func addChildViewController(childVcName: String, title: String, imageName: String) {
// 获取项目的命名空间
guard let nameSpace = Bundle.main.infoDictionary!["CFBundleExecutable"] as? String else {
// 如果命名空间获取失败,直接返回
return
}
// 根据传进来的控制器字符串获取与之对应的class
guard let childVcClass = NSClassFromString(nameSpace + "." + childVcName) else {
// 如果childVcClass获取失败,直接退出
return
}
// 将获取到的AnyClass转成具体的控制器类型
guard let childVcType = childVcClass as? UIViewController.Type else {
// 如果转类型失败,则直接返回
return
}
// 创建对应的控制器对象
let childVc = childVcType.init()
// 设置子控制器的属性
childVc.title = title // 设置子控制器的标题
childVc.tabBarItem.image = UIImage(named: imageName + "-n_25x19_") // live-n_25x19_
childVc.tabBarItem.selectedImage = UIImage(named: imageName + "-p_25x19_") // live-p_25x19_
// 包装导航控制器
let childVcNav = UINavigationController(rootViewController: childVc)
// 添加子控制器
addChildViewController(childVcNav)
}
5、循环语句
在Swift中,while循环语句与Objective-C中的while循环语句差不多。但是,在Swift中使用while循环还是需要注意:1、条件语句中只能有一个表达式,而且必须是布尔类型的表达式;2、循环体中如果需要用到循环变量,必须在while循环语句执行之前对循环变量进行初始化。
Swift中的repeat-while语句和Objective-C中的do-while循环语句类似。repeat-while语句是事后判断循环条件的结构,它没有初始化值,循环次数是不可知的,并且不管循环条件是否满足,它都会至少执行一次。循环条件满足时,继续执行循环体;循环条件不满足时,退出循环体:
// 寻找平方数小于1000的最大整数
var i: Int64 = 0
repeat {
i += 1
} while i * i < 1000
print("i = \(i)") // 32
print("i * i = \(i * i)") // 1024
Swift 3以后不能再使用C语言风格的for循环了,并且它只能与in结合,构成for-in循环,用来对某个范围或者集合进行遍历。这个比较简单,就不举实例了。
6、跳转语句
跳转语句用于改变程序的执行顺序,或者实现程序的跳转。Swift中有5中跳转语句:break、continue、fallthrough、return和throw。暂时先介绍前面三种,return留到函数里面讲,throw留到错误处理里面再讲。
break语句一般用于while、repeat-while和for-in循环中,其作用是强制退出循环体,不再执行剩下的语句。break语句也可以用于switch分支语句,但是在Swift中,switch语句默认在每一个分支之后隐式的添加了一个break,如果手动添加break语句,对程序的执行也没什么影响。
在循环体中使用break语句有两种形式,即带标签和不带标签。带标签的break语句使程序跳出标签所指示的循环体,而不带标签的break语句使程序跳出所在层的循环体。我们来演示一下带标签的break:
// 带标签的break
label1: for i in 0..<5 {
label2: for j in (1...5).reversed() {
if j == i {
break label1 // 当j == i时,直接跳出最外层的循环体
}
print("(i, j) = (\(i), \(j))")
}
}
print("循环结束")
运行结果为:
(i, j) = (0, 5)
(i, j) = (0, 4)
(i, j) = (0, 3)
(i, j) = (0, 2)
(i, j) = (0, 1)
(i, j) = (1, 5)
(i, j) = (1, 4)
(i, j) = (1, 3)
(i, j) = (1, 2)
循环结束
默认情况下,break只会跳出最内层的循环体,如果需要跳出外层循环体,可以像上面那样用带标签的break语句进行标识。在有循环嵌套时,适当的使用带标签的break语句可以有效提高程序执行效率。
continue语句用于结束本次循环,然后接着继续进行条件判断,直到条件不满足时才终止。continue语句也有两种形式,即带标签的continue和不带标签的continue。默认情况下,continue语句也是只会跳出内层循环的本次循环,如果需要跳出外层循环,则需要用标签进行指示:
// 带标签的continue
label1: for i in 0..<5 {
label2: for j in (1...5).reversed() {
if j == i {
continue label1
}
print("(i, j) = (\(i), \(j))")
}
}
print("循环结束")
运行结果为:
(i, j) = (0, 5)
(i, j) = (0, 4)
(i, j) = (0, 3)
(i, j) = (0, 2)
(i, j) = (0, 1)
(i, j) = (1, 5)
(i, j) = (1, 4)
(i, j) = (1, 3)
(i, j) = (1, 2)
(i, j) = (2, 5)
(i, j) = (2, 4)
(i, j) = (2, 3)
(i, j) = (3, 5)
(i, j) = (3, 4)
(i, j) = (4, 5)
循环结束
fallthrough语句是穿透语句,只能用在switch语句中。在Swift中,switch语句默认是不穿透的,如果需要人为穿透,则需要添加关键字fallthrough。
7、值绑定
值绑定我们在上面讲guard时就用过。所谓的值绑定,就是在控制语句中,将表达式的值临时赋值给一个常量或者变量,从而使得这个常量或者变量能够在该控制语句中使用。值绑定多用于if和guard语句,也可以用于switch语句。
if语句中的值绑定是在条件表达式部分进行的。绑定的过程是,先将表达式赋值给一个变量或者常量,然后再判断这个值是否为nil,如果不为nil,则绑定成功并进入true分支,否则进入false分支。以下载网络图片为例,一般要先判断下载地址是否有效,然后再判断数据下载是否成功,只有当这两个条件都满足时,才能将下载的图片设置到图片控件上去:
// 对imageView控件进行懒加载
fileprivate lazy var imageView: UIImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 300))
override func viewDidLoad() {
super.viewDidLoad()
// 先校验图片url地址是否正确
if let url = URL(string: "https://gss0.baidu.com/-fo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/0b55b319ebc4b745359202e2c8fc1e178a82153b.jpg") {
// 再校验图片有没有下载成功
if let imageData = try? Data(contentsOf: url) {
// 将图片控件添加到父控件中
view.addSubview(imageView)
// 设置imageView的位置
imageView.center = view.center
// 设置imageView的图片
imageView.image = UIImage(data: imageData)
}
}
}
guard语句值绑定和if语句的值绑定用法差不多,但是更为直观。用guard语句值绑定来改写上面的示例如下:
// 对imageView控件进行懒加载
fileprivate lazy var imageView: UIImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 300))
override func viewDidLoad() {
super.viewDidLoad()
// 先校验图片url地址是否正确
guard let url = URL(string: "https://gss0.baidu.com/-fo3dSag_xI4khGko9WTAnF6hhy/zhidao/pic/item/0b55b319ebc4b745359202e2c8fc1e178a82153b.jpg") else {
return
}
// 再校验图片有没有下载成功
guard let imageData = try? Data(contentsOf: url) else {
return
}
// 将图片控件添加到父控件中
view.addSubview(imageView)
// 设置imageView的位置
imageView.center = view.center
// 设置imageView的图片
imageView.image = UIImage(data: imageData)
}
在上面的代码中,try?那里程序抛出了异常,需要进行处理,具体的处理方式参见《项目基本架构的搭建》的第二部分第3小节。
where语句
where语句一般用在控制语句中,对条件进行过滤。比如说,switch语句和for循环。它还可以用在泛型中。以for循环为例:
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 遍历数组中所有大于5的元素
for i in arr where i > 5 {
print("i = \(i)")
}
程序执行结果为:
i = 6
i = 7
i = 8
i = 9
i = 10