ios -- 教你如何轻松学习Swift语法(三) 完结篇
前言:swift语法基础篇(二)来了,想学习swift的朋友可以拿去参考哦,有兴趣可以相互探讨,共同学习哦.
一.自动引用计数
1.自动引用计数工作机制
1.1 swift和oc一样,采用自动引用计数来管理内存
1.2 当有强引用指向对象,对象的引用计数 +1 , 强引用消失,自动计数 -1
1.3 如果对象的引用计数为0 , 那么该对象会被销毁
2.循环引用
2.1 什么是循环引用?
两个(或多个)对象互相强引用
2.2 循环引用对项目有什么影响
循环引用会让对象不会被销毁,一直保存在内存中,可能导致项目运行不畅
2.3 怎么解决强引用问题?
只需要让其中一个对象对另外一个对象的引用变为弱引用即可
在swift中用waek 相当于OC中的 __weak ,或者使用 unowned 相当于OC中的 __unsafe_unretained
3.weak 和 unowned的区别
3.1 相同点:
都是一个弱引用,不会对对象进行retain
3.2 不同点
3.21 weak(__weak) :当弱引用指向的对象销毁时,该引用会指向nil 所以用weak指向的数据类型为可选类型
3.22 unowned(__unsafe_unretained) :当弱引用指向的对象销毁时,依然指向原来的内存地址, 容易产生错误(野指针/访问僵尸对象)
3.23 unowned不支持可选类型
二.可选链
1.什么是可选链?
简单的说,就是可选类型的对象组成的链条
2.为什么会产生可选链?
2.1 假设有三个类, 人,狗,玩具
2.2 人里面有狗这个属性,狗里面有玩具这个属性, 玩具里面有价格这个属性
2.3 把玩具这个对象赋值给狗(让狗拥有玩具), 把狗这个对象赋值给人(让人拥有这只狗)
2.4 想要通过人来修改玩具的价格,就需要 person.dog.toy.price 来修改
2.5 person.dog这个值得类型是可选类型 ,因为人的狗属性可能为nil 属性,想要使用person.dog ,必须要强制解包
2.6 person.dog.toy也是可选类型,像这样由可选类型的对象组成的链条就是可选链
3.可选链注意点
3.1 利用可选链赋值的时候一定要解包
3.2 利用可选链取值的时候也不要忘记解包
3.3 利用可选链调用方法的时候 也要先解包
4.利用可选链赋值, 取值,调用方法
4.1 给可选链赋值:
1 person.dog!.toy!.price = 50 太危险 强制解包,如果没值,直接程序崩溃 2 3 if let dog = person.dog { 4 if let toy = dog.toy { 5 toy.price = 50 6 } 这样解包虽然安全,但是太麻烦 7 }
苹果在swift中推荐使用这种方式来给可选链赋值
1 person.dog?.toy?.price = 50 2 //当person.dog 为nil的时候,后面的操作就不再执行
4.2 从可选链取值: 从可选链中取出的值得类型一定是可选类型 (有可能取不到)
let price = person.dog?.toy?.price
4.3 可选链调用方法:系统会自动判断可选类型是否有值
person.dog?.toy?.flying()
三.协议
1.如何定义协议
1.1 swift中协议的方式和类,结构体,枚举相似
protocol SomeProtocol { // 协议方法 }
1.2 例如:定义一个运动协议
1 protocol SportProtocol { 2 func playBasketball() 3 func playFootball() 4 }
2.声明一个类,并且遵守协议
2.1 声明一个基类(不继承其它类),并遵守协议
1 class SomeClass:FirstProtocol,AnotherProtocol { 2 // 类的内容 3 // 实现协议中的方法 4 } 5 6 例如: 7 class Person : SportProtocol { 8 var name : String = "" 9 10 func playBasketball() { 11 print("打篮球") 12 } 13 14 func playFootball() { 15 print("踢足球") 16 } 17 }
2.2 类继承自其他类,并遵守协议
1 class SomeClass:SomeSuperClass, FirstProtocol,AnotherProtocol { 2 // 类的内容 3 // 实现协议中的方法 4 }
3.OC swift不支持多继承, 但是可以通过协议,间接实现多继承
4.协议的继承关系
4.1 swift中的及协议和OC(NSObject)中的不同 是:NSObjectProtocol
1 protocol CrazySportProtocol : NSObjectProtocol { 2 func jumping() 3 }
4.2 一个协议,可以遵守另一个协议
1 protocol SportProtocol : CrazySportProtocol { 2 func playBasketball() 3 }
当一个类遵守了这个协议(SportProtocol) 相当于也遵守了CrazySportProtocol 协议, 所以必须实现这两个协议中的方法
5.协议的可选性
5.1 OC中协议可以定义为可选和必选,默认是必选的
5.2 默认情况下,swift中的协议都是必须实现的 ,否则编译器会报错
5.3 在swift中如何让协议成为可选的(不用必须实现)
要在协议前加 @objc ,可以保留OC某些特性,在方法前加optional 该方法就是可选的了
在实现协议方法时,在方法前面也要加@objc
1 @objc protocol SportProtocol { 2 func playBasketball() 3 func playFootball() 4 //加optional该方法就成为可选的了 5 optional func jumping() 6 } 7 8 class Person: SportProtocol { 9 @objc func playBasketball() { 在方法前也要加上关键字@objc,不管是可选还是必选 10 } 11 @objc func playFootball() { 12 } 13 @objc func jumping() { 14 } 15 }
6.协议在代理模式中的使用
6.1 一般来说协议都用weak来修饰(弱引用)
6.2 weak只能用来修饰类
6.3 在swift中协议既可以被类遵守,也可以被结构体,枚举遵守
6.4 如何让协议只能被类准守
在协议名称后面加上 :class 即可
四.闭包
1.什么是闭包?
闭包和OC中的block非常相似,一般都用来函数的回调
2.block的回顾
block作为属性的格式: `@property (nonatomic, strong) void(^finishedCallback)(NSString *)`;
block作为参数的定义格式:` (void (^)(NSString * str))finishedCallback`
3.闭包的格式:
(参数列表) -> (返回值类型)
4.闭包的使用
5.尾随闭包
1 // 尾随闭包 : 如果函数的最后一个参数是一个闭包.那么可以将函数调用写成尾随闭包 2 //就是把闭包写到()的后面, 本来是写在()里面的 3 tools?.loadData() { (result) in 4 print("在ViewController中获取到数据:\(result)") 5 } 6 7 // 如果函数有且只有一个参数,并且是一个闭包, 那么()也可以省略 8 tools?.loadData { (result) in 9 print("在ViewController中获取到数据:\(result)") 10 }
6.闭包的循环引用
6.1 一般在定义工具类的时候,会在工具类的方法中用到闭包
6.2 当工具类对闭包有强引用,一个控制器又调用包含该闭包的方法,在闭包方法中使用控制器的属性,就会发生循环引用
6.3 控制器调用方法,就会对工具类有一个强引用, 闭包又拿到控制器的属性,闭包对象就对控制器有一个强引用
6.4 在内存中就相当于这种表现
7.怎么解决闭包的循环引用
与oc中类型,只需要把闭包对控制器的引用改为弱引用
8.怎么改?
当闭包修改控制器的属性时,拿到控制器的属性时,把self(控制器)改成weakself即可
weak var weakself : ViewController? = self
五.swift项目的目录结构简介
1.swift项目目录中没有.h和.m的文件, 只有一个.swift的文件,相当于
2.swift目录中.swift文件就相当于oc中的.h和.m文件
3.在swift中,调用项目中的其他源文件不需要导入头文件 (一个 .swift文件就是一个源文件)
六.懒加载
1.懒加载的介绍
1.1 和OC中不同,swift有专门的关键字实现懒加载
1.2 懒加载本质:当第一次使用时再加载,而且只会被加载一次
2.swift中用lazy关键字来实现懒加载
2.1 懒加载格式
lazy var 变量: 类型 = { 创建变量代码 }()
= 后面是一个闭包 苹果推荐用闭包来实现懒加载,可在闭包中对变量属性进行初始化
2.2 懒加载的使用
1 lazy var names : [String] = { 2 return ["why", "yz", "lmj"] 3 }()
当执行到上面代码的时候,names不会被加载到内存中, 当names第一次使用时,才会被加载
无论names使用多少次,只会被加载一次,也就是说内存中只有一个names属性地址
七.swift中的常见注释
1.单行注释
和OC中的单行注释一样 使用 // 注释内容
2.多行注释
和OC中的多行注释格式一样 /* 注释内容 */
不同的是,swift中多行注释可以嵌套使用
3.文档注释
与oc中不一样 , swift中 用 /// 注释内容 来实现文档注释
4.分组注释
和oc不一样 oc: #pragma mark - 注释内容
swift: //MARK : - 注释内容
八.访问权限
1.internal :内部的
1.1 当不指定具体的访问权限时,默认为internal
1.2 internal的访问权限: 在当前项目(包)的任何地方都能访问
2.private : 私有的
private的访问权限: 在当前源文件中能够访问 一个 .swift文件就是一个源文件
3.public :公共的
3.1 public的访问权限 : 可以跨包访问
3.2 包的概念: 就是一个项目或一个框架 UIKit也是一个框架
九.异常处理
1.在swift中,如果一个方法的最后有一个throws,那么这个方法能抛出异常
正则表达式就能抛出异常:
NSRegularExpression(pattern: <#T##String#>, options: <#T##NSRegularExpressionOptions#>)
2.如果一个方法抛出异常,必须要对异常进行处理,否则编译报错
3.异常处理的三种方式
3.1 try : 手动处理异常,可以拿到异常(error)
要在方法前面加上try 而且外面要用do 包装
//try方式 --> 手动处理异常, 并且可以获取到最终的异常结果 do { //如果有异常error有值 let regex = try NSRegularExpression(pattern: "", options: .CaseInsensitive) } catch { //通过error拿到异常结果 print(error) }
3.2 try? : 系统处理异常
try?方式 : 如果有异常,则返回nil,如果没有异常,则返回结果 结果(regex)为可选类型
let regex = try? NSRegularExpression(pattern: "", options: .CaseInsensitive)
regex?.matchesInString("", options: [], range: NSMakeRange(0, 0))
3.3 try! :告诉系统不可能有异常
try!方式(不推荐) 注意:一旦发生异常,程序就会崩溃
let regex = try! NSRegularExpression(pattern: "", options: .CaseInsensitive)
十.如何抛出异常
1.在方法参数的后面加上 throws ,一定要有返回值
2.在某些具体的情况下抛出异常
比如:传的参数不对等等 ,内部要对参数进行判断
3.抛出的异常,一般定义为枚举类型 枚举后面要跟上 ErrorType 这种类型
十一.OC和swift相互调用
1.swift中调用oc
1.1 创建一个桥接文件 (.h的文件) 文件名一般为 Bridge.h
1.2 在桥接文件中导入oc的头文件
1.3 配置桥接文件 工程 —> BuildSetting —> 搜索bridging 在后面写入Bridge.h 的相对路径
2.oc中调用swift
2.1 项目名称要规范 (不能有中文和特殊字符)
2.2 swift中的类,属性,方法名 前面要加 public
2.3 在oc文件中导入 工程名-Swift.h 的头文件 工程名-Swift.h 系统会自动生成