Swift第四周(第一月)總結(jié)

沉迷學(xué)習(xí),日漸消瘦,一天不學(xué)習(xí),渾身難受。

學(xué)習(xí)Swift已過(guò)一個(gè)月,已經(jīng)從零基礎(chǔ)到入門(mén),能夠逐漸理順?biāo)季w,找到關(guān)鍵點(diǎn)。

swift副本.jpg

協(xié)議

  • 協(xié)議是方法的集合(計(jì)算屬性相當(dāng)于就是方法),可以把看似不相關(guān)的對(duì)象的公共行為放到一個(gè)協(xié)議中

注釋: 協(xié)議在Swift開(kāi)發(fā)中大致有三種作用:

  1. 能力 - 遵循了協(xié)議就意味著具備了某種能力
  2. 約定 - 遵循了協(xié)議就一定要實(shí)現(xiàn)協(xié)議中的方法
  3. 角色 - 一個(gè)類(lèi)可以遵循多個(gè)協(xié)議, 一個(gè)協(xié)議可以被多個(gè)類(lèi)遵循, 遵循協(xié)議就意味著扮演了某種角色, 遵循多個(gè)協(xié)議就意味著可以扮演多種角色
  • Swift中的繼承是單一繼承(一個(gè)類(lèi)只能有一個(gè)父類(lèi)), 如果希望讓一個(gè)類(lèi)具備多重能力可以使用協(xié)議來(lái)實(shí)現(xiàn)(C++里面是通過(guò)多重繼承來(lái)實(shí)現(xiàn)的, 這是一種非常狗血的做法)

  • 協(xié)議中全是抽象概念(只有聲明沒(méi)有實(shí)現(xiàn)) 遵循協(xié)議的類(lèi)可以各自對(duì)協(xié)議中的計(jì)算屬性和方法給出自己的實(shí)現(xiàn)版本 這樣當(dāng)我們面向協(xié)議編程時(shí)就可以把多態(tài)的優(yōu)勢(shì)發(fā)揮到淋漓盡致 可以寫(xiě)出更通用更靈活的代碼(符合開(kāi)閉原則)

  • 實(shí)現(xiàn)開(kāi)閉原則最關(guān)鍵有兩點(diǎn):

  1. 抽象是關(guān)鍵(在設(shè)計(jì)系統(tǒng)的時(shí)候一定要設(shè)計(jì)好的協(xié)議);
  2. 封裝可變性(橋梁模式 - 將不同的可變因素封裝到不同的繼承結(jié)構(gòu)中)

注釋:接口(協(xié)議)隔離原則: 協(xié)議的設(shè)計(jì)要小而專(zhuān)不要大而全
協(xié)議的設(shè)計(jì)也要高度內(nèi)聚

protocol Flyable {
    
    func fly()
}
protocol Fightable {
    
    func fight()
}

協(xié)議擴(kuò)展

協(xié)議擴(kuò)展 - 可以在協(xié)議擴(kuò)展中給協(xié)議中的方法提供默認(rèn)實(shí)現(xiàn)
也就是說(shuō)如果某個(gè)類(lèi)遵循了協(xié)議但是沒(méi)有實(shí)現(xiàn)這個(gè)方法就直接使用默認(rèn)實(shí)現(xiàn)
那么這個(gè)方法也就相當(dāng)于是一個(gè)可選方法(可以實(shí)現(xiàn)也可以不實(shí)現(xiàn))

extension Fightable {
    
    func fight() {
        print("正在打架")
    }
}
// 協(xié)議的繼承
protocol NiuBi: Flyable, Fightable { 
    func dive()
}
class Boxer: Fightable {
    
    @objc func fight() {
        print("正在進(jìn)行格斗.")
    }
}
  • 依賴(lài)倒轉(zhuǎn)原則(面向協(xié)議編程)
  1. 聲明變量的類(lèi)型時(shí)應(yīng)該盡可能使用協(xié)議類(lèi)型
  2. 聲明方法參數(shù)類(lèi)型時(shí)應(yīng)該盡可能使用協(xié)議類(lèi)型
  3. 聲明方法返回類(lèi)型時(shí)應(yīng)該盡可能使用協(xié)議類(lèi)型
et x: protocol<Flyable, Fightable> = Superman()
let y: NiuBi = Superman()
  • 協(xié)議組合
let array: [protocol<Flyable, Fightable>] = []

計(jì)算機(jī)屬性:

計(jì)算機(jī)的硬件由五大部件構(gòu)成:
運(yùn)算器、控制器、存儲(chǔ)器、輸入設(shè)備、輸出設(shè)備
運(yùn)算器 + 控制器 => CPU (中央處理器)
存儲(chǔ)器 => 內(nèi)存 (RAM - Random Access Memory)

程序員可以使用的內(nèi)存大致分為五塊區(qū)域:

棧 (stack) - 我們定義的局部變量/臨時(shí)變量都是放在棧上

  • 特點(diǎn): 小、快
    堆 (heap) - 我們創(chuàng)建的對(duì)象都是放在堆上的
  • 特點(diǎn): 大、慢
    靜態(tài)區(qū) (static area)
  • 數(shù)據(jù)段 - 全局量
  • 只讀數(shù)據(jù)段 - 常量
  • 代碼段 - 函數(shù)和方法
值和類(lèi)型的區(qū)別:
  • 區(qū)別1: 結(jié)構(gòu)的對(duì)象是值類(lèi)型, 類(lèi)的對(duì)象是引用類(lèi)型
    值類(lèi)型在賦值的時(shí)候會(huì)在內(nèi)存中進(jìn)行對(duì)象的拷貝
    引用類(lèi)型在賦值的時(shí)候不會(huì)進(jìn)行對(duì)象拷貝只是增加了一個(gè)引用

** 結(jié)論:** 我們自定義新類(lèi)型時(shí)優(yōu)先考慮使用類(lèi)而不是結(jié)構(gòu)除非我們要定義的是一種底層的數(shù)據(jù)結(jié)構(gòu)(保存其他數(shù)據(jù)的類(lèi)型)

引用類(lèi)型的類(lèi)
let stu1 = Student1(name: "駱昊", age: 35)
var stu3 = stu1     // 此處內(nèi)存中仍然只有一個(gè)學(xué)生對(duì)象
stu3.name = "羅小號(hào)"
stu3.age = 18
print(stu1.name)
print(stu1.age)
  • 值類(lèi)型的結(jié)構(gòu)
    區(qū)別2: 結(jié)構(gòu)會(huì)自動(dòng)生成初始化方法
et stu2 = Student2(name: "駱昊", age: 35)
var stu4 = stu2     // 此處內(nèi)存中會(huì)復(fù)制一個(gè)新的學(xué)生對(duì)象
stu4.name = "王大錘"
stu4.age = 18
print(stu2.name)
print(stu2.age)
  • 區(qū)別3: 結(jié)構(gòu)中的方法在默認(rèn)情況下是不允許修改結(jié)構(gòu)中的屬性除非加上mutating關(guān)鍵字:
mutating func getOlder() {
        age += 1
    }
}
  • 其他:
在Swift中同名函數(shù)只要參數(shù)列表不同是可以共存的 這個(gè)叫函數(shù)的重載
func changeName(inout name: String) {
    name = "王大錘"
}

協(xié)議委托回調(diào):

有的時(shí)候某個(gè)對(duì)象要做某件事情但其自身又沒(méi)有能力做這件事情,這個(gè)時(shí)候就可以使用委托回調(diào)的編程模式讓別的對(duì)象來(lái)做這件事情

實(shí)現(xiàn)委托回調(diào)的編程模式有以下幾個(gè)步驟:

  1. 設(shè)計(jì)一個(gè)協(xié)議(被委托方必須要遵循協(xié)議才能給別的對(duì)象當(dāng)委托)
protocol CanvasDelegate: class {

協(xié)議里面的方法就是要委托其他對(duì)象做的事情

unc showMessage(canvas: Canvas, message: String)
}
  1. 委托方添加一個(gè)屬性其類(lèi)型是遵循了協(xié)議的被委托方
class Canvas: UIView {
    // 2. 委托方添加一個(gè)屬性其類(lèi)型是遵循了協(xié)議的被委托方
     weak var delegate: CanvasDelegate?
     var renjuBoard = RenjuBoard()
    var isAutoMode = false
    func clearBoard() {
        renjuBoard.reset()
        setNeedsDisplay()
    }
    func randomMove() {
        let row = Int(arc4random_uniform(15))
        let col = Int(arc4random_uniform(15))
        if renjuBoard[row, col] {
            renjuBoard[row, col] = renjuBoard.isBlackTurn
            setNeedsDisplay()
        }
    }
  1. 自己做不了的事情委托給別的對(duì)象來(lái)做
delegate?.showMessage(self, message: renjuBoard.isBlackTurn ? "白棋勝" : "黑棋勝")

其他:

 Swift 2中的guard大法, Swift 3中據(jù)說(shuō)要廢掉
        guard !isAutoMode else { return }
        // guard !renjuBoard.isGameOver else { return }
  • 索引器:
    // 索引器語(yǔ)法 - 可以直接對(duì)棋盤(pán)對(duì)象做下標(biāo)運(yùn)算來(lái)放置棋子
    subscript(row: Int, col: Int) -> Bool {
        get { return board[row][col] == .Space }
        set(isBlack) {
            if board[row][col] == .Space {
                board[row][col] = isBlack ? .Black : .White
                isBlackTurn = !isBlackTurn
            }

指派構(gòu)造器:

指派構(gòu)造器(designated)
    required init(name: String, age: Int) {
        print("創(chuàng)建一個(gè)人!")
        self.name = name
        self.age = age
    }

注釋:指派構(gòu)造器前面加上required可以將構(gòu)造器指定為必要構(gòu)造器
所謂的必要構(gòu)造器意味著子類(lèi)也要提供一模一樣的構(gòu)造器

  • 下面的語(yǔ)句必須寫(xiě)在調(diào)用自己的初始化方法之后否則major屬性會(huì)被賦上不正確的值:
        self.major = major
        self.init(name: name, age: age)
        self.major = major
        初始化的第一階段
          1. 初始化自己特有的屬性
       self.major = major
       // 子類(lèi)只能調(diào)用直接父類(lèi)的構(gòu)造器
        // 子類(lèi)構(gòu)造器必須調(diào)用父類(lèi)的非便利構(gòu)造器(指派構(gòu)造器)
 super.init()    // compiler error
        //  2. 調(diào)用父類(lèi)的初始化方法
        super.init(name: name, age: age)
 //初始化的第二階段
       // 此處可以調(diào)用對(duì)象的方法因?yàn)閷?duì)象已經(jīng)完成了初始化
        study()
    }
      func study() {
        print("\(name)正在學(xué)習(xí).")
    }
     deinit {
        print("學(xué)生對(duì)象嗝屁了!")
    }
}
class Teacher: Person {
    deinit {
        print("老師對(duì)象嗝屁了!")
    }
}
  • 棧 - FILO 先進(jìn)后出的結(jié)構(gòu)
    創(chuàng)建任何子類(lèi)對(duì)象的時(shí)候一定是先創(chuàng)建了父類(lèi)對(duì)象
    var stu: Person = Student()
    引用轉(zhuǎn)移(會(huì)導(dǎo)致原來(lái)對(duì)象上的引用計(jì)數(shù)-1 新對(duì)象引用計(jì)數(shù)+1)
 stu = Teacher()
 stu = Person()
  • Swift的自動(dòng)釋放池
    通過(guò)向autoreleasepool函數(shù)中傳入一個(gè)閉包來(lái)實(shí)現(xiàn)
    autoreleasepool { () -> () in
    自動(dòng)釋放池中的對(duì)象引用在池的邊界會(huì)收到引用計(jì)數(shù)-1的消息
> 將來(lái)做iOS開(kāi)發(fā)時(shí)如果某個(gè)地方會(huì)創(chuàng)建很多的臨時(shí)對(duì)象.   那么最好在此處設(shè)置一個(gè)自動(dòng)釋放池避免內(nèi)存瞬時(shí)峰值過(guò)高造成閃退
     let stu1 = Student()
     let stu2 = stu1
 }

離開(kāi)自動(dòng)釋放池時(shí) stu1會(huì)收到引用計(jì)數(shù)-1消息 stu2也會(huì)收到引用計(jì)數(shù)-1消息

  • 如果程序中出現(xiàn)了類(lèi)與類(lèi)之間雙向關(guān)聯(lián)關(guān)系 必須要將其中一端設(shè)置為weak引用,否則將會(huì)形成循環(huán)引用導(dǎo)致ARC無(wú)法釋放內(nèi)存

注釋:
推薦使用
如果允許使用可空類(lèi)型通常使用weak來(lái)破除循環(huán)引用
如果員工關(guān)聯(lián)的部門(mén)對(duì)象被釋放了那么dept會(huì)被賦值為nil
如果要繼續(xù)給dept對(duì)象發(fā)消息程序不會(huì)崩潰
weak var dept: Dept?

 謹(jǐn)慎使用
 如果不允許使用可空類(lèi)型就必須使用unowned來(lái)破除循環(huán)引用
 需要注意的是如果員工對(duì)象關(guān)聯(lián)的部門(mén)對(duì)象被釋放了
 如果還要通過(guò)員工對(duì)象去操作它所關(guān)聯(lián)的部門(mén)對(duì)象將導(dǎo)致程序崩潰
 EXC_BAD_ACCESS

泛型 (generic)

  • 讓類(lèi)型不再是程序中的硬代碼(寫(xiě)死的東西)
    1.定義虛擬類(lèi)型:
// 定義一個(gè)虛擬類(lèi)型T, 調(diào)用函數(shù)時(shí)根據(jù)傳入的參數(shù)類(lèi)型來(lái)決定T到底是什么
func mySwap<T>(inout a: T, inout _ b: T) {
    let temp = a
    a = b
    b = temp
}

2.泛型限定

// <T: Comparable>限定T類(lèi)型必須是遵循了Comparable協(xié)議的類(lèi)型
func myMin<T: Comparable>(a: T, _ b: T) -> T {
    return a < b ? a : b
}

注釋:wift中的類(lèi)、結(jié)構(gòu)和枚舉都可以使用泛型:

struct Stack<T> {
    var data: [T] = []
    
    // 入棧
    mutating func push(elem: T) {
        data.append(elem)
    }
    
    // 出棧
    mutating func pop() -> T {
        return data.removeLast()
    }
    
    var isEmpty: Bool {
        get { return data.count == 0 }
    }
}

拋錯(cuò)誤異常

  • 如果一個(gè)方法拋出了異常 那么在聲明方法時(shí)必須要寫(xiě)上throws關(guān)鍵字
    throws關(guān)鍵字是提醒方法的調(diào)用者方法可能會(huì)出狀況 調(diào)用時(shí)要寫(xiě)try:
init(num: Int, den: Int) throws {
        _num = num
        _den = den
        if _den == 0 {
            // 如果程序中出現(xiàn)問(wèn)題就拋出錯(cuò)誤(異常)
            // 被throw關(guān)鍵字拋出的必須是遵循ErrorType協(xié)議的東西
            throw FractionError.ZeroDenominator
        }
        else {
            simplify()
            normalize()
        }
    }

But:
1.如果能夠確保方法調(diào)用時(shí)不出異常那么可以在try關(guān)鍵字后加!
2.這樣就可以在不寫(xiě)do...catch的情況下調(diào)用可能出狀況的方法

注釋:如果能夠保證代碼不出錯(cuò)可以在try后面加!
1.如果不確定代碼是否出錯(cuò)可以在try后面加?
2.需要注意的是有?的地方會(huì)產(chǎn)生Optional(可空類(lèi)型)
稍后可能還需要對(duì)可空類(lèi)型進(jìn)行拆封, 拆封方式有二:
1. 不安全的做法: xxx!
2. 安全的做法: 用if let = xxx { }進(jìn)行拆封

    let f1 = try? Fraction(num: 3, den: 0)
    let f2 = try? Fraction(num: 0, den: 9)
    
    if let a = f1, b = f2 {
        let f3 = a + b
        print(f3.info)
    }
    else {
        print("無(wú)效的分?jǐn)?shù)無(wú)法進(jìn)行加法運(yùn)算")
    }
}
foo

注釋:
1.對(duì)于可能出狀況的代碼要放在do...catch中執(zhí)行.
2.在可能出狀況的方法前還要寫(xiě)上try表示嘗試著執(zhí)行
3.如果在do中沒(méi)有出現(xiàn)任何狀況那么catch就不會(huì)執(zhí)行
4.如果do中出現(xiàn)了狀況代碼就不會(huì)再向下繼續(xù)執(zhí)行而是轉(zhuǎn)移到catch中
5.在do的后面可以跟上多個(gè)catch用于捕獲不同的異常狀況 但是最多只有一個(gè)catch會(huì)被執(zhí)行

do {
    let f1 = try Fraction(num: 3, den: 4)
    let f2 = try Fraction(num: 0, den: 9)

    print(f1.info)
    print(f2.info)

    let f3 = f1 + f2
    print(f3.info)
    let f4 = f1 - f2
    print(f4.info)
    let f5 = f1 * f2
    print(f5.info)
    let f6 = try f1 / f2
    print(f6.info)
}
catch FractionError.ZeroDenominator {
    print("瓜西西的, 分母不能為0!!!")

總結(jié):

相對(duì)于這幾周的語(yǔ)法相對(duì)于比較枯燥和難一些,攻破了這個(gè)之后的路就能更為順暢一些,在之后的日子更要努力。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,563評(píng)論 19 139
  • day one 依賴(lài)倒轉(zhuǎn)原則(面向協(xié)議編程) 聲明變量的類(lèi)型時(shí)應(yīng)該盡可能使用協(xié)議類(lèi)型 聲明方法參數(shù)類(lèi)型時(shí)應(yīng)該盡可能...
    saman0閱讀 434評(píng)論 0 0
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,697評(píng)論 18 399
  • 1.項(xiàng)目經(jīng)驗(yàn) 2.基礎(chǔ)問(wèn)題 3.指南認(rèn)識(shí) 4.解決思路 ios開(kāi)發(fā)三大塊: 1.Oc基礎(chǔ) 2.CocoaTouch...
    扶光啟玄閱讀 5,204評(píng)論 0 13
  • Date: 20th Nov, 2016 Location: Veolia 陽(yáng)光熱電,哈爾濱 Holder: Ve...
    io晶晶閱讀 258評(píng)論 0 0

友情鏈接更多精彩內(nèi)容