Swift第三周學習總結

協議

1.協議:協議只給出方法的聲明,不給出具體方法的實現過程,協議是方法的集合(計算屬性相當于就是方法),誰遵循協議就要定義方法。
2.協議在Swift中的作用:

  • 1.能力 - 遵循了協議就意味著具備了某種能力
  • 2.約定 - 遵循了協議就一定要實現協議中的方法
  • 3.角色 - 一個類可以遵循多個協議,一個協議也可以被多個類遵循,遵循協議就意味著扮演了某種角色,遵循了多個協議就意味著可以扮演多個角色

3.協議與繼承的區別在于:Swift中的繼承是單一繼承(一個類只能有一個父類),如果希望讓一個類具有多重能可以使用協議來實現。


例:我們先建一個Father的類,這個類有吃、喝、嫖、賭四種行為(方法)

class Father {
    func eat(){
        
    }
    
    func drink(){
        
    }
    
    func wench(){
        
    }
    
    func gamble(){
        
    }
}

然后我們再創建一個Monk的類,和一個Musician的類

protocol Monk {
    func eatVegitable()
    
    func chant()
    
    func knockTheBell()
}

protocol Musician{
    func playPiano()
    
    func playViolin()
}

最后創建一個Son的類,它繼承了Father,并且遵循了Monk、Musician協議

class Son: Father, Monk, Musician {
    override func gamble() {
        print("正在斗地主")
    }
    func eatVegitable() {
    }
    
    func chant() {
    }
    
    func knockTheBell() {
    }
    
    func playPiano() {
    }
    
    func playViolin() {
    }
    
    func steal(){
    }
}

這個Son類繼承于Father當然就擁有了它的屬性,同時它遵循了Monk、Musician協議,就擁有了它們的能力,但前提是必須要實現它們的方法。
所以當我們創建一個Son的對象它就擁有了如下的方法:


屏幕快照 2016-08-19 下午8.09.54.png

4.協議的繼承
5.協議的組合

let array: [protocol<Monk,Musician>] = [Son()]

當然協議也有多態。
6.協議的擴展
協議擴展 - 可以在協議擴展中給協議中的方法提供默認實現
也就是說如果某個類遵循了協議但是沒有實現這個方法就直接使用默認實現
那么這個方法也就相當于是一個可選方法(可以實現也可以不實現)

extension Fightable{
    func fight(){
        print("正在打架.")
    }
}

總結:協議中全是抽象概念(只有聲明沒有實現),遵循協議的類可以各自對協議中的計算屬性和方法給出自己的實現版本,這樣當我們面向協議編程時就可以把多態的優勢發揮到淋漓盡致,可以寫出更通用更靈活的代碼(符合開閉原則)

  • 實現開閉原則最關鍵有兩點:
    • 1.抽象是關鍵(在設計系統的時候一定要設計好協議);
    • 2.封裝可變性(橋梁模式- 將不同的可變因素封裝到不同的繼承結構中)
    • 3.接口(協議)隔離原則:協議的設計一定要小而專不要大而全,協議的設計也要高內聚

7.委托回調和代理模式

關于這兩種方法我們可以舉一個考生找槍手代考的例子:

//槍手代考: 委托回調
protocol ExamDelegate: class {
    
    func answerTheQuestion()
}

class LazyStudent {
    var name: String
    weak var delegate: ExamDelegate? //委托方添加一個屬性,其類型是遵循了協議的被委托方
    
    init(name: String) {
        self.name = name
    }
    
    func joinExam() {
        print("姓名: \(name)")
        delegate?.answerTheQuestion()
    }
}

class Gunman: ExamDelegate {
    
    func answerTheQuestion() {
        print("奮筆疾書各種答案")
    }
}

let stu = LazyStudent(name: "王大錘")
let gun = Gunman()
stu.delegate = gun
stu.joinExam()

//槍手代考: 代理模式
protocol ExamCandidate: class {
    
    func answerTheQuestion()
}

class LazyStudent: ExamCandidate {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    func answerTheQuestion() {
    }
}

class Gunman: ExamCandidate {
    var name: String
    var target: LazyStudent? //代理方添加一個屬性,其類型是被代理方
    
    init(name: String) {
        self.name = name
    }
    
    func answerTheQuestion() {
        if let stu = target {
            print("姓名: \(stu.name)")
            print("奮筆疾書答案")
            print("提交試卷")
        }
    }
}

let stu = LazyStudent(name: "王大錘")
let gun = Gunman(name: "駱昊")
gun.target = stu
gun.answerTheQuestion()

** 注意:**就學生和槍手這個例子而言,委托回調相當于學生只是帶了個作弊器,而代理模式才是真正的槍手幫學生代考,這兩種方法還是有一定的區別的。

結構體

1.我們分別創建一個類和一個結構體:

class Student1 {
    var name: String
    var age: Int
    
    init (name: String, age: Int){
        self.name = name
        self.age = age
    }
    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
    }
}

2.創建對象,找出區別

let stu1 = Student1(name: "羅大號", age: 35)
var stu3 = stu1  //此處內存中仍然只有一個學生對象
stu3.name = "羅小號"
stu3.age = 18
print(stu1.name)
print(stu1.age)

執行結果為:

羅小號
18
Program ended with exit code: 0

創建結構體的對象:

let stu2 = Student2(name: "翠花", age: 26)
var stu4 = stu2 //此處內存中復制了一個學生對象
stu4.name = "荷花"
stu4.age = 18
print(stu2.name)
print(stu2.age)

執行結果為:

翠花
26
Program ended with exit code: 0

總結: 區別1:重點:結構的對象是值類型,類的對象是引用類型,值的類型在賦值的時候會在內存中進行對象的拷貝,引用類型在賦值的時候不會進行對象拷貝,只是增加了一個引用.
區別2: 結構會自動生成初始化方法
區別3: 結構中的方法在默認情況下是不允許修改結構中的屬性的,除非加上mutating
結論: 我們自定義新類型是優先考慮使用類而不是結構,除非我們要定義的是一種底層的數據結構

自動引用計數(ARC)

1.我們先創建幾個類:

class Person {
    init(){
        print("創建一個人")
    }
    
    deinit{
        print("人嗝屁了")
    }
}

class Teacher: Person {
    override init() {
        super.init()
        print("創建一個老師")
    }
    deinit{
        print("老師嗝屁")
    }
    
}
class Student: Person{
    override init() {
        super.init()
        print("創建一個學生對象!")
    }
    
    deinit {
        print("學生對象嗝屁!")
    }
}

說明:1.因為創建對象的方式多種多樣,所以可以定義多種初始化方法,對象就可以使用多種初始化方法。
2.子類只能調用直接父類的初始化方法,子類構造器必須調用父類的非便利構造器(指派構造器)

2.//創建一個學生對象,然后用stu1去引用它,所以此時學生對象引用計數為1
var stu1: Student? = Student()
//此處沒有創建新的學生對象,原來的學生對象的引用計數+1
var stu2 = stu1 var stu3 = stu1
//學生對象引用計數-1
stu1 = nil
//學生對象引用計數-1
stu2 = nil
//學生對象引用計數-1
//當學生對象引用計數為0時,ARC會自動清理內存釋放學生對象
//ARC即時性的內存清理 優于java的Garbage Collection(垃圾回收)
stu3 = nil
//弱(weak)修飾的引用不會導致自動引用計數增加,默認是強引用(會增加引用計數)
weak var stu2 = stu1 weak var stu3 = stu1
3.釋放內存的方法

  • 1.如果想釋放內存,程序員可以手動將一個引用賦值成nil
    stu1 = nil
  • 2.stu是一個局部變量,在函數調用結束后局部變量就消失了,所以學生對象的引用計數也就變成0了,所以會被ARC釋放
func foo(){
    let stu = Student()
    print(stu)
}
foo()

結果如下:

創建一個人
創建一個學生對象!
Day08_17_01.Student
學生對象嗝屁!
人嗝屁了
Program ended with exit code: 0
  • 3.引用轉移(會導致原來對象上的引用計數-1,新對象+1)
var stu: Person = Student()
stu = Teacher()
stu = Person()

打印結果如下:

創建一個人
創建一個老師
學生對象嗝屁!
人嗝屁了
創建一個人
老師嗝屁
人嗝屁了
Program ended with exit code: 0

從結果可以看出:創建子類對象的時候一定是先創建了父類對象;棧(FIOL)是先進后出的結構。

  • 4.自動釋放池:通過向atuoreleasepool函數傳入一個閉包來實現
autoreleasepool { () -> () in
    //自動釋放池中的對象引用在池的邊界引用計數會收到引用計數-1的消息
    //將來做IOS開發是如果在某個地方會創建很多的臨時對象
    //那么最好在此處設置一個自動釋放池避免內存瞬時峰值過高
    let stu1 = Student()
    let stu2 = stu1
}
離開自動釋放池時 stu1會收到引用計數-1的消息,stu2也會收到引用計數-1的消息

4.類與類之間的循環引用
我們來創建兩個類(部門和員工)相互引用:

class Dept{
    weak var manager: Emp?

  init(){
        print("創建一個部門")
    }
    deinit{
        print("銷毀一個部門")
    }
}
class Emp {
    var dept: Dept?
    init(){
        print("創建一個員工")
    }
    deinit{
        print("銷毀一個員工")
    }
  • 如上形成循環引用,導致ARC無法釋放內存

解決方法:1.如果程序中出現了類與類之間的雙向關聯關系 必須將其中一端設置成weak引用,如果允許使用可空類型通常使用weak來破除循環引用
2.如果不允許使用可空類型就必須使用unowned來破除循環引用

class Emp {
    weak var dept: Dept?
    init(){
        print("創建一個員工")
    }
    deinit{
        print("銷毀一個員工")
    }

或者這樣:

class Emp {
    unowned var dept: Dept
    init(dept: Dept){
    self.dept = dept
        print("創建一個員工")
    }
    deinit{
        print("銷毀一個員工")
    }
//需要注意的是如果員工對象關聯的部門對象被釋放了  
//如果還要通過員工對象去操作它所關聯的部門對象將導致程序崩潰
// EXC_BAD_ACCESS

泛型

1.泛型(generic) - 讓類型不再是程序中的硬代碼(寫死的東西)
2.定義一個虛擬的類型T(也可以用其它字符代替),調用函數是根據傳入的參數類型來決定T到底是什么

func mySwap<T>(inout a: T, inout _ b: T){
    (a,b) = (b,a)
}

var x = "hello", y = "good"
mySwap(&x, &y)
print(x,y)  //結果:good hello

3.泛型限定
<T: Comparable>限定T類型必須是遵循了Comparable協議的類型

func myMin<T: Comparable>(a: T, _ b: T) -> T {
    return a > b ? a : b
}

var z = "hello", s = "good"
print(myMin(z, s)) //打印結果:hello

上述代碼中虛擬類型T是不可以直接比較的,但是遵循了Comparable協議后就能比較了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內容

  • [TOC] 協議 協議中全是抽象概念(只有聲明沒有實現), 遵循協議的類可以各自對協議中的計算屬性和方法給出自己的...
    檜霖閱讀 357評論 0 3
  • 1. 集合(Set) (1)集合的定義: (2)集合寫法: 舉例: (4)對集合的操作: 2. 字典(Dictio...
    老韓在簡書閱讀 536評論 1 2
  • 集合 存儲方式離散,通過hash方式存儲。集合中沒有重復元素 字典(存放鍵值對組合的容器) 字典中的每個元素都是由...
    離殤丶閱讀 181評論 0 0
  • day one 依賴倒轉原則(面向協議編程) 聲明變量的類型時應該盡可能使用協議類型 聲明方法參數類型時應該盡可能...
    saman0閱讀 379評論 0 0
  • ___海閱讀 232評論 1 2