Swift——第三周的爬坑之路

協(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
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市眷蚓,隨后出現(xiàn)的幾起案子鼻种,更是在濱河造成了極大的恐慌,老刑警劉巖沙热,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叉钥,死亡現(xiàn)場離奇詭異,居然都是意外死亡篙贸,警方通過查閱死者的電腦和手機投队,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爵川,“玉大人敷鸦,你說我怎么就攤上這事∏薰保” “怎么了扒披?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長圃泡。 經(jīng)常有香客問我碟案,道長,這世上最難降的妖魔是什么颇蜡? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任价说,我火速辦了婚禮,結(jié)果婚禮上风秤,老公的妹妹穿的比我還像新娘鳖目。我一直安慰自己,他們只是感情好缤弦,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布领迈。 她就那樣靜靜地躺著,像睡著了一般碍沐。 火紅的嫁衣襯著肌膚如雪惦费。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天抢韭,我揣著相機與錄音薪贫,去河邊找鬼。 笑死刻恭,一個胖子當著我的面吹牛瞧省,可吹牛的內(nèi)容都是我干的扯夭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鞍匾,長吁一口氣:“原來是場噩夢啊……” “哼交洗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起橡淑,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤构拳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后梁棠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體置森,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年符糊,在試婚紗的時候發(fā)現(xiàn)自己被綠了凫海。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡男娄,死狀恐怖行贪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情模闲,我是刑警寧澤建瘫,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站尸折,受9級特大地震影響啰脚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翁授,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一拣播、第九天 我趴在偏房一處隱蔽的房頂上張望晾咪。 院中可真熱鬧收擦,春花似錦、人聲如沸谍倦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昼蛀。三九已至宴猾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叼旋,已是汗流浹背仇哆。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夫植,地道東北人讹剔。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓油讯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親延欠。 傳聞我的和親對象是個殘疾皇子陌兑,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容