協(xié)議
1.定義:協(xié)議是方法的集合剂买,可以把看似不相關(guān)的對象的公共行為放到一個協(xié)議中狭莱。
2.協(xié)議自身的意義:Swift中的繼承是單一繼承(一個類只能有一個父類), 如果希望讓一個類具備多重能力可以使用協(xié)議來實現(xiàn)鹅髓。
3.協(xié)議在Swift開發(fā)中大致有三種作用:
- 能力 - 遵循了協(xié)議就意味著具備了某種能力。
- 約定 - 遵循了協(xié)議就一定要實現(xiàn)協(xié)議中的方法。
- 角色 - 一個類可以遵循多個協(xié)議, 一個協(xié)議可以被多個類遵循, 遵循協(xié)議就意味著扮演了某種角色, 遵循多個協(xié)議就意味著可以扮演多種角色鳞贷。
4.實例:
//首先進行協(xié)議的創(chuàng)建
protocol Flyable {
func fly()
}
protocol Fightable {
func fight()
}
//再進行實體類的創(chuàng)建并繼承協(xié)議
class Bird: Flyable {
func fly() {
print("鳥兒扇動翅膀飛行.")
}
}
class Boxer: Fightable {
func fight() {
print("正在進行格斗.")
}
}
而此時想要建立一個超人類,卻發(fā)現(xiàn)協(xié)議不“夠”用了虐唠,那么可以進行協(xié)議的擴展和協(xié)議之間的繼承
//協(xié)議的擴展 - 可以在協(xié)議擴展中給協(xié)議中的方法提供默認實現(xiàn)
// 也就是說如果某個類遵循了協(xié)議但是沒有實現(xiàn)這個方法就直接使用默認實現(xiàn)
// 那么這個方法也就相當于是一個可選方法(可以實現(xiàn)也可以不實現(xiàn))
extension Fightable {
func fight() {
print("正在打架")
}
}
// 協(xié)議的繼承
protocol Super: Flyable, Fightable {
func dive()
}
//創(chuàng)建超人類
class Superman: Super {
func fly() {
print("超人使用超能力飛行.")
}
// func fight() {
// print("超人正在和邪惡勢力干仗.")
// }
func dive() {
print("超人正在潛水.")
}
}
協(xié)議的總結(jié):
1.依賴倒轉(zhuǎn)原則(面向協(xié)議編程)
- 聲明變量的類型時應該盡可能使用協(xié)議類型
- 聲明方法參數(shù)類型時應該盡可能使用協(xié)議類型
- 聲明方法返回類型時應該盡可能使用協(xié)議類型
2.協(xié)議的開閉原則:
- 協(xié)議中全是抽象概念(只有聲明沒有實現(xiàn)) 遵循協(xié)議的類可以各自對協(xié)議中的計算屬性和方法給出自己的實現(xiàn)版本 這樣當我們面向協(xié)議編程時就可以把多態(tài)的優(yōu)勢發(fā)揮到淋漓盡致 可以寫出更通用更靈活的代碼(符合開閉原則)
3.接口(協(xié)議)隔離原則: 協(xié)議的設計要小而專不要大而全
結(jié)構(gòu)
1.定義:用于保存基層數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)搀愧;與類相似,只是將定義的關(guān)鍵字改為了struct。
2.與類的區(qū)別
- 區(qū)別 1: 結(jié)構(gòu)的對象是值類型, 類的對象是引用類型
- 值類型在賦值的時候會在內(nèi)存中進行對象的拷貝
- 引用類型在賦值的時候不會進行對象拷貝只是增加了一個引用
- 區(qū)別 2: 結(jié)構(gòu)會自動生成初始化方法
- 區(qū)別 3: 結(jié)構(gòu)中的方法在默認情況下是不允許修改結(jié)構(gòu)中的屬性除非加上mutating關(guān)鍵字
3.代碼演示:
class Student1 {
var name: String
var age: Int
var tel: String?
init(name: String, age: Int) {
self.name = name
self.age = age
}
func getOlder() {
age += 1
}
func study(courseName: String) {
print("\(name)正在學習.")
}
}
struct Student2 {
var name: String
var age: Int
func study(courseName: String) {
print("\(name)正在學習.")
}
mutating func getOlder() {
age += 1
}
}
// 引用類型的類
let stu1 = Student1(name: "Xyk_", age: 18)
var stu3 = stu1 // 此處內(nèi)存中仍然只有一個學生對象
stu3.name = "-kyX"
stu3.age = 15
print(stu1.name)
print(stu1.age)
// 值類型的結(jié)構(gòu)
let stu2 = Student2(name: "Xyk_kyX", age: 18)
var stu4 = stu2 // 此處內(nèi)存中會復制一個新的學生對象
stu4.name = "Xyk_kyX_Xyk"
stu4.age = 15
print(stu2.name)
print(stu2.age)
//打印結(jié)果:
-kyX
15
Xyk_kyX
18
//這里的打印結(jié)果可以看出:
//1:用struct創(chuàng)建的學生在被“賦值”給學生的以后咱筛,沒有被更改姓名和年齡
//2:用類創(chuàng)建的學生在被“賦值”給學生的以后搓幌,被更改姓名和年齡
釋放內(nèi)存
代碼演示1:
class Person {
var name: String
var age: Int
// 指派構(gòu)造器前面加上required可以將構(gòu)造器指定為必要構(gòu)造器
// 所謂的必要構(gòu)造器意味著子類也要提供一模一樣的構(gòu)造器
// 指派構(gòu)造器(designated)
required init(name: String, age: Int) {
print("創(chuàng)建一個人!")
self.name = name
self.age = age
}
// 便利構(gòu)造器(convenience)
convenience init() {
self.init(name: "無名氏", age: 20)
}
deinit {
print("人嗝屁了!")
}
}
class Student: Person {
var major: String
required init(name: String, age: Int) {
major = "未知"
super.init(name: name, age: age)
}
convenience init(name: String, age: Int, major: String) {
// 下面的語句必須寫在調(diào)用自己的初始化方法之后否則major屬性會被賦上不正確的值
// self.major = major
self.init(name: name, age: age)
self.major = major
// 初始化的第一階段
// 1. 初始化自己特有的屬性
// self.major = major
// 子類只能調(diào)用直接父類的構(gòu)造器
// 子類構(gòu)造器必須調(diào)用父類的非便利構(gòu)造器(指派構(gòu)造器)
// super.init() // compiler error
// 2. 調(diào)用父類的初始化方法
// super.init(name: name, age: age)
// 初始化的第二階段
// 此處可以調(diào)用對象的方法因為對象已經(jīng)完成了初始化
// study()
}
func study() {
print("\(name)正在學習.")
}
deinit {
print("學生對象嗝屁了!")
}
}
class Teacher: Person {
deinit {
print("老師對象嗝屁了!")
}
}
// 創(chuàng)建一個學生對象 然后用stu1去引用它 所以此時學生對象引用計數(shù)為1
var stu1: Student? = Student()
// 此處沒有創(chuàng)建新的學生對象 原來的學生對象的引用計數(shù)+1
var stu2 = stu1
// 同上 原來的學生對象的引用計數(shù)+1
var stu3 = stu2
// 學生對象引用計數(shù)-1
stu1 = nil
// 學生對象引用計數(shù)-1
stu2 = nil
// 學生對象引用計數(shù)-1
// 當學生對象引用計數(shù)為0時 ARC會自動清理內(nèi)存釋放學生對象
// ARC即時性的內(nèi)存清理 優(yōu)于Java中的Garbage Collection(垃圾回收)
stu3 = nil
代碼演示2:
class Emp {
// 推薦使用
// 如果允許使用可空類型通常使用weak來破除循環(huán)引用
// 如果員工關(guān)聯(lián)的部門對象被釋放了那么dept會被賦值為nil
// 如果要繼續(xù)給dept對象發(fā)消息程序不會崩潰
// weak var dept: Dept?
// 謹慎使用
// 如果不允許使用可空類型就必須使用unowned來破除循環(huán)引用
// 需要注意的是如果員工對象關(guān)聯(lián)的部門對象被釋放了
// 如果還要通過員工對象去操作它所關(guān)聯(lián)的部門對象將導致程序崩潰
// EXC_BAD_ACCESS
unowned var dept: Dept
init(dept: Dept) {
print("創(chuàng)建一個員工")
self.dept = dept
}
deinit {
print("銷毀一個員工")
}
}
class Dept {
var manager: Emp?
init() {
print("創(chuàng)建一個部門")
}
deinit {
print("銷毀一個部門")
}
}
func bar() {
// let person = Person()
let dept = Dept()
let emp = Emp(dept: dept)
dept.manager = emp
}
bar()
泛型:
1.定義一個虛擬類型T, 調(diào)用函數(shù)時根據(jù)傳入的參數(shù)類型來決定T到底是什么
2.泛型限定:<T: Comparable>限定T類型必須是遵循了Comparable協(xié)議的類型
3.讓類型不再是程序中的硬代碼
func bubbleSort<T: Comparable>(array: [T]) -> [T] {
var newArray = array
for i in 0..<newArray.count - 1 {
var swapped = false
for j in 0..<newArray.count - 1 - i {
if newArray[j] > newArray[j + 1] {
mySwap(&newArray[j], &newArray[j + 1])
swapped = true
}
}
if !swapped {
break
}
}
return newArray
}