Swift基础知识补充(二)

  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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容