Protocol(協(xié)議)

// swift的協(xié)議很重要
// 協(xié)議 protocol

//“協(xié)議 定義了一個藍圖,規(guī)定了用來實現(xiàn)某一特定任務(wù)或者功能的方法、屬性,以及其他需要的東西。類、結(jié)構(gòu)體或枚舉都可以遵循協(xié)議,并為協(xié)議定義的這些要求提供具體實現(xiàn)。某個類型能夠滿足某個協(xié)議的要求,就可以說該類型遵循這個協(xié)議”
//“除了遵循協(xié)議的類型必須實現(xiàn)的要求外,還可以對協(xié)議進行擴展,通過擴展來實現(xiàn)一部分要求或者實現(xiàn)一些附加功能,這樣遵循協(xié)議的類型就能夠使用這些功能。”

//1. 協(xié)議語法

protocol SomeProtocol{
    //這里是協(xié)議的定義部分
}

//“要讓自定義類型遵循某個協(xié)議,在定義類型時,需要在類型名稱后加上協(xié)議名稱,中間以冒號(:)分隔。遵循多個協(xié)議時,各協(xié)議之間用逗號(,)分隔:”

struct SomeStructure:SomeProtocol{
    //結(jié)構(gòu)體的定義部分
}

// “擁有父類的類在遵循協(xié)議時,應(yīng)該將父類名放在協(xié)議名之前,以逗號分隔”

//class SomeClass: SomeSuperClass,FirstProtocol,AnotherProtocol{
    //這里是類的定義部分
//}

//2. 屬性要求
//“協(xié)議可以要求遵循協(xié)議的類型提供特定名稱和類型的實例屬性或類型屬性。協(xié)議不指定屬性是存儲型屬性還是計算型屬性,它只指定屬性的名稱和類型。此外,協(xié)議還指定屬性是可讀的還是可讀可寫的?!?br> //“如果協(xié)議要求屬性是可讀可寫的,那么該屬性不能是常量屬性或只讀的計算型屬性。如果協(xié)議只要求屬性是可讀的,那么該屬性不僅可以是可讀的,如果代碼需要的話,還可以是可寫的?!?br> //“協(xié)議總是用 var 關(guān)鍵字來聲明變量屬性,在類型聲明后加上 { set get } 來表示屬性是可讀可寫的,可讀屬性則用 { get } 來表示:”

protocol propertyProtocol{
    var mustBesettable:Int {
        get set
    }
    var doesNotNeedToBeSettable:Int{
        get
    }
}

//“在協(xié)議中定義類型屬性時,總是使用 static 關(guān)鍵字作為前綴。當(dāng)類類型遵循協(xié)議時,除了 static 關(guān)鍵字,還可以使用 class 關(guān)鍵字來聲明類型屬性:”

protocol AnotherProtocol{
    static var someTypeProperty:Int{
        get set
    }
}

//示例

protocol FullyNamed{
    var fullName:String {
        get
    }
}
struct Person:FullyNamed {
    var fullName: String
}
let john = Person(fullName:"john Appleseed")

class Starship:FullyNamed{
    var prefix : String?
    var name : String
    init(name:String,prefix:String? = nil) {
        self.name = name
        self.prefix = prefix
    }
    var fullName: String {
        return (prefix != nil ? prefix! + "" : "") + name
    }
}
var ncc1701 = Starship(name:"EnterPrise",prefix:"USS")
ncc1701.fullName //USSEnterPrise

//3.方法要求
//“協(xié)議可以要求遵循協(xié)議的類型實現(xiàn)某些指定的實例方法或類方法。這些方法作為協(xié)議的一部分,像普通方法一樣放在協(xié)議的定義中,但是不需要大括號和方法體??梢栽趨f(xié)議中定義具有可變參數(shù)的方法,和普通方法的定義方式相同。但是,不支持為協(xié)議中的方法的參數(shù)提供默認(rèn)值”
//“正如屬性要求中所述,在協(xié)議中定義類方法的時候,總是使用 static 關(guān)鍵字作為前綴。當(dāng)類類型遵循協(xié)議時,除了 static 關(guān)鍵字,還可以使用 class 關(guān)鍵字作為前綴:”

protocol MethodProtocol{
    static func someTypeMethod()
}

//示例

protocol RandomNumberGennerator{
    func random() -> Double
}
class LinearCongruentialGenerator:RandomNumberGennerator{
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
    func random() -> Double {
        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy: m))
        return lastRandom / m
    }
}

//4. Mutating方法要求
// “有時需要在方法中改變方法所屬的實例。例如,在值類型(即結(jié)構(gòu)體和枚舉)的實例方法中,將 mutating 關(guān)鍵字作為方法的前綴,寫在 func 關(guān)鍵字之前,表示可以在該方法中修改它所屬的實例以及實例的任意屬性的值?!?br> //“如果你在協(xié)議中定義了一個實例方法,該方法會改變遵循該協(xié)議的類型的實例,那么在定義協(xié)議時需要在方法前加 mutating 關(guān)鍵字。這使得結(jié)構(gòu)體和枚舉能夠遵循此協(xié)議并滿足此方法要求?!?br> //“注意 實現(xiàn)協(xié)議中的 mutating 方法時,若是類類型,則不用寫 mutating 關(guān)鍵字。而對于結(jié)構(gòu)體和枚舉,則必須寫 mutating 關(guān)鍵字。”

protocol Togglable{
    mutating func toggle()
}
enum OnOffSwitch:Togglable{
    case Off,On
    mutating func toggle() {
        switch self {
        case .Off:
            self = .On
        case .On:
            self = .Off
        }
    }
}
var ligthSwitch = OnOffSwitch.Off
ligthSwitch.toggle()

//4. 構(gòu)造器要求
//“協(xié)議可以要求遵循協(xié)議的類型實現(xiàn)指定的構(gòu)造器。你可以像編寫普通構(gòu)造器那樣,在協(xié)議的定義里寫下構(gòu)造器的聲明,但不需要寫花括號和構(gòu)造器的實體:”

protocol InitProtocol{
    init(someParameter:Int)
}

//“你可以在遵循協(xié)議的類中實現(xiàn)構(gòu)造器,無論是作為指定構(gòu)造器,還是作為便利構(gòu)造器。無論哪種情況,你都必須為構(gòu)造器實現(xiàn)標(biāo)上 required 修飾符”

class InitClass:InitProtocol{
    required init(someParameter: Int) {
        //構(gòu)造器的實現(xiàn)
    }
}

//“使用 required 修飾符可以確保所有子類也必須提供此構(gòu)造器實現(xiàn),從而也能符合協(xié)議?!?br> //“注意 如果類已經(jīng)被標(biāo)記為 final,那么不需要在協(xié)議構(gòu)造器的實現(xiàn)中使用 required 修飾符,因為 final 類不能有子類?!?br> //“如果一個子類重寫了父類的指定構(gòu)造器,并且該構(gòu)造器滿足了某個協(xié)議的要求,那么該構(gòu)造器的實現(xiàn)需要同時標(biāo)注 required 和 override 修飾符:

protocol DoubleProtocol{
    init()
}

class SuperClass{
    init() {
    }
}
class subClass: SuperClass,DoubleProtocol {
    //因為遵循協(xié)議,需要加上required,
   //因為繼承自父類,需要加上 override
    required override init() {
        //這里是構(gòu)造器實現(xiàn)
    }
}

//5.協(xié)議作為類型
//“盡管協(xié)議本身并未實現(xiàn)任何功能,但是協(xié)議可以被當(dāng)做一個成熟的類型來使用?!?br> /*
“作為函數(shù)、方法或構(gòu)造器中的 參數(shù)類型或返回值類型
作為常量、變量或?qū)傩缘念愋?br> 作為數(shù)組、字典或其他容器中的 元素類型”
*/

class Dice{
    let sides : Int
    let generator : RandomNumberGennerator
    init(sides:Int,generator:RandomNumberGennerator) {
        self.sides = sides
        self.generator = generator
    }
    func roll() -> Int {
        return Int(generator.random() * Double(sides))+1
    }
}

//“上例中定義了一個 Dice 類,用來代表桌游中擁有 N 個面的骰子。Dice 的實例含有 sides 和 generator 兩個屬性,前者是整型,用來表示骰子有幾“個面,后者為骰子提供一個隨機數(shù)生成器,從而生成隨機點數(shù)。
//“generator 屬性的類型為 RandomNumberGenerator,因此任何遵循了 RandomNumberGenerator 協(xié)議的類型的實例都可以賦值給 generator,除此之外并無其他要求。
//“Dice 類還有一個構(gòu)造器,用來設(shè)置初始狀態(tài)。構(gòu)造器有一個名為 generator,類型為 RandomNumberGenerator 的形參。在調(diào)用構(gòu)造方法創(chuàng)建 Dice 的實例時,可以傳入任何遵循 RandomNumberGenerator 協(xié)議的實例給 generator

var d6 = Dice(sides:6,generator:LinearCongruentialGenerator())
for _ in 1...5{
    print("Random dice roll is \(d6.roll())")
}

//6.委托代理模式
// “委托是一種設(shè)計模式,它允許類或結(jié)構(gòu)體將一些需要它們負(fù)責(zé)的功能委托給其他類型的實例,委托模式的實現(xiàn)很簡單:定義協(xié)議來封裝那些需要被委托的功能,這樣就能確保遵循協(xié)議的類型能提供這些功能。委托模式可以用來響應(yīng)特定的動作,或者接收外部數(shù)據(jù)源提供的數(shù)據(jù),而無需關(guān)心外部數(shù)據(jù)源的類型。

protocol DiceGame{
    var dice : Dice{get}
    func play()
}
protocol DiceGameDelegate {
    func gameDidStart(_ game:DiceGame)
    func game(_ game: DiceGame,didStartNewTurnWithDiceRoll diceRoll:Int)
    func gameDidEnd(_ game:DiceGame)
}

//“DiceGame 協(xié)議可以被任意涉及骰子的游戲遵循。 DiceGameDelegate 協(xié)議可以被任意類型遵循,用來追蹤 DiceGame 的游戲過程?!?/p>

class SnakesAndLadders:DiceGame{
    let finalSquare = 25
    let dice = Dice(sides:6,generator:LinearCongruentialGenerator())
    var square = 0
    var board : [Int]
    init() {
        board = [Int](repeating:0,count:finalSquare+1)
        board[03] = +08;board[06] = +11; board[09] = +09; board[10] = +02
        board[14] = -10;board[19] = -11; board[22] = -02; board[24] = -08
    }
    var delegate : DiceGameDelegate?
    func play() {
        square = 0
        delegate?.gameDidStart(self)
        gameLoop:while square != finalSquare{
            let diceRoll = dice.roll()
            delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
            switch square + diceRoll {
            case finalSquare:
                break gameLoop
            case let newSquare where newSquare > finalSquare:
                continue gameLoop
            default:
                square += diceRoll
                square += board[square]
            }
        }
        delegate?.gameDidEnd(self)
    }
}

//“這個版本的游戲封裝到了 SnakesAndLadders 類中,該類遵循了 DiceGame 協(xié)議,并且提供了相應(yīng)的可讀的 dice 屬性和 play() 方法。( dice 屬性在構(gòu)造之后就不再改變,且協(xié)議只要求 dice 為可讀的,因此將 dice 聲明為常量屬性”
//“游戲使用 SnakesAndLadders 類的 init() 構(gòu)造器來初始化游戲。所有的游戲邏輯被轉(zhuǎn)移到了協(xié)議中的 play() 方法,play() 方法使用協(xié)議要求的 dice 屬性提供骰子搖出的值。
//“注意,delegate 并不是游戲的必備條件,因此 delegate 被定義為 DiceGameDelegate 類型的可選屬性。因為 delegate 是可選值,因此會被自動賦予初始值 nil。隨后,可以在游戲中為 delegate 設(shè)置適當(dāng)?shù)闹怠?br> //“因為 delegate 是一個 DiceGameDelegate 類型的可選屬性,因此在 play() 方法中通過可選鏈?zhǔn)秸{(diào)用來調(diào)用它的方法。若 delegate 屬性為 nil,則調(diào)用方法會優(yōu)雅地失敗,并不會產(chǎn)生錯誤。若 delegate 不為 nil,則方法能夠被調(diào)用,并傳遞 SnakesAndLadders 實例作為參數(shù)?!?/p>

class DiceGameTracker:DiceGameDelegate{
    var numberOfTurns = 0
    func gameDidStart(_ game: DiceGame) {
        numberOfTurns = 0
        if game is SnakesAndLadders{
            print("Started a new game of Snakes and Ladders")
        }
        print("the game is using a \(game.dice.sides) sides dice")
    }
    func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
        numberOfTurns += 1
        print("rolled a \(diceRoll)")
    }
    func gameDidEnd(_ game: DiceGame) {
        print("the game lasted for \(numberOfTurns) turns")
    }
}

//“DiceGameTracker 實現(xiàn)了 DiceGameDelegate 協(xié)議要求的三個方法,用來記錄游戲已經(jīng)進行的輪數(shù)。當(dāng)游戲開始時,numberOfTurns 屬性被賦值為 0,然后在每新一輪中遞增,游戲結(jié)束后,打印游戲的總輪數(shù)。”

//運行該游戲

let tracker = DiceGameTracker()
let game = SnakesAndLadders()
game.delegate = tracker
game.play()
//打印
//Started a new game of Snakes and Ladders
//the game is using a 6 sides dice
//rolled a 3
//rolled a 5
//rolled a 4
//rolled a 5
//the game lasted for 4 turns

//6.通過擴展添加協(xié)議一致性
//“即便無法修改源代碼,依然可以通過擴展令已有類型遵循并符合協(xié)議。擴展可以為已有類型添加屬性、方法、下標(biāo)以及構(gòu)造器,因此可以符合協(xié)議中的相應(yīng)要求
//注意 通過擴展令已有類型遵循并符合協(xié)議時,該類型的所有實例也會隨之獲得協(xié)議中定義的各項功能。

protocol TextReprresentable{
    var textualDescription : String {get}
}
extension Dice :TextReprresentable{
    var textualDescription: String{
        return "A \(sides) side dice"
    }
}

//“通過擴展遵循并符合協(xié)議,和在原始定義中遵循并符合協(xié)議的效果完全相同。協(xié)議名稱寫在類型名之后,以冒號隔開,然后在擴展的大括號內(nèi)實現(xiàn)協(xié)議要求的內(nèi)容?!?/p>

let d12 = Dice(sides:12,generator:LinearCongruentialGenerator())
print(d12.textualDescription)
//打印 A 12 side dice

extension SnakesAndLadders:TextReprresentable{
    var textualDescription: String{
        return "A game of Snakes and ladders with \(finalSquare) squares"
    }
}
print(game.textualDescription)
// 打印 A game of Snakes and ladders with 25 squares

//7. 通過擴展遵循協(xié)議
//“當(dāng)一個類型已經(jīng)符合了某個協(xié)議中的所有要求,卻還沒有聲明遵循該協(xié)議時,可以通過空擴展體的擴展來遵循該協(xié)議:”

struct Hamster{
    var name : String
    var textualDescription:String {
        return "A hamster named \(name)"
    }
}
extension Hamster:TextReprresentable{}
let simonTheHamster = Hamster(name:"simon")
print(simonTheHamster.textualDescription)
//打印A hamster named simon

//“注意 即使?jié)M足了協(xié)議的所有要求,類型也不會自動遵循協(xié)議,必須顯式地遵循協(xié)議。

//8.協(xié)議類型的集合
//“協(xié)議類型可以在數(shù)組或者字典這樣的集合中使用”

let things:[TextReprresentable] = [game,d12,simonTheHamster]
for thing in things {
    print(thing.textualDescription)
}
//打印 A game of Snakes and ladders with 25 squares
//A 12 side dice
//A hamster named simon

//“thing 是 TextRepresentable 類型而不是 Dice,DiceGame,Hamster 等類型,即使實例在幕后確實是這些類型中的一種。由于 thing 是 TextRepresentable 類型,任何 TextRepresentable 的實例都有一個 textualDescription 屬性,所以在每次循環(huán)中可以安全地訪問 thing.textualDescription?!?/p>

//9. 協(xié)議的繼承
//“協(xié)議能夠繼承一個或多個其他協(xié)議,可以在繼承的協(xié)議的基礎(chǔ)上增加新的要求。協(xié)議的繼承語法與類的繼承相似,多個被繼承的協(xié)議間用逗號分隔:”

protocol inheritingProtocol:SomeProtocol,AnotherProtocol{
    //這里是協(xié)議的定義部分
}

protocol PrettyTextRepresentable:TextReprresentable{
    var prettyTextualDescrition : String {get}
}

//“例子中定義了一個新的協(xié)議 PrettyTextRepresentable,它繼承自 TextRepresentable 協(xié)議。任何遵循 PrettyTextRepresentable 協(xié)議的類型在滿足該協(xié)議的要求時,也必須滿足 TextRepresentable 協(xié)議的要求?!?/p>

extension SnakesAndLadders:PrettyTextRepresentable{
    var prettyTextualDescrition: String{
        var outPut = textualDescription + ":\n"
        for index in 1...finalSquare {
            switch board[index] {
            case let ladder where ladder > 0:
                outPut += "↑"
            case let snake where snake < 0:
                outPut += "↓"
            default:
                outPut += "〇"
            }
        }
        return outPut
    }
}

//“上述擴展令 SnakesAndLadders 遵循了 PrettyTextRepresentable 協(xié)議,并提供了協(xié)議要求的 prettyTextualDescription 屬性。每個 PrettyTextRepresentable 類型同時也是 TextRepresentable 類型,所以在 prettyTextualDescription 的實現(xiàn)中,可以訪問 textualDescription 屬性。然后,拼接上了冒號和換行符。”
print(game.prettyTextualDescrition)
//打印 〇〇↑〇〇↑〇〇↑↑〇〇〇↓〇〇〇〇↓〇〇↓〇↓〇

//10.類類型專屬協(xié)議
//“你可以在協(xié)議的繼承列表中,通過添加 class 關(guān)鍵字來限制協(xié)議只能被類類型遵循,而結(jié)構(gòu)體或枚舉不能遵循該協(xié)議。class 關(guān)鍵字必須第一個出現(xiàn)在協(xié)議的繼承列表中,在其他繼承的協(xié)議之前”

protocol SomeClassOnlyProtocol:class,inheritingProtocol{
    //類類型專屬協(xié)議
}

//注意:當(dāng)協(xié)議定義的要求需要遵循協(xié)議的類型必須是引用語義而非值語義時,應(yīng)該采用類類型專屬協(xié)議”

//11.協(xié)議合成
//“有時候需要同時遵循多個協(xié)議,你可以將多個協(xié)議采用 SomeProtocol & AnotherProtocol 這樣的格式進行組合,稱為 協(xié)議合成(protocol composition)。你可以羅列任意多個你想要遵循的協(xié)議,以與符號(&)分隔”

protocol Named{
    var name : String{get}
}
protocol Aged {
    var age : Int {get}
}
struct People:Named,Aged{
    var name : String
    var age : Int
    init(_ name:String,_ age:Int) {
        self.name = name
        self.age = age
    }
}
func wishHappyBirthday(to celebrator:Named&Aged){
    print("happy birthday, \(celebrator.name),you are \(celebrator.age)")
}
let birthdayPerson = People("jack",12)
wishHappyBirthday(to: birthdayPerson)
//打印 happy birthday, jack,you are 12

//“Named 協(xié)議包含 String 類型的 name 屬性。Aged 協(xié)議包含 Int 類型的 age 屬性。Person 結(jié)構(gòu)體遵循了這兩個協(xié)議。wishHappyBirthday(to:) 函數(shù)的參數(shù) celebrator 的類型為 Named & Aged。這意味著它不關(guān)心參數(shù)的具體類型,只要參數(shù)符合這兩個協(xié)議即可?!?br> //“注意 協(xié)議合成并不會生成新的、永久的協(xié)議類型,而是將多個協(xié)議中的要求合成到一個只在局部作用域有效的臨時協(xié)議中。

//12.檢查協(xié)議的一致性
//“你可以使用類型轉(zhuǎn)換中描述的 is 和 as 操作符來檢查協(xié)議一致性,即是否符合某協(xié)議,并且可以轉(zhuǎn)換到指定的協(xié)議類型。檢查和轉(zhuǎn)換到某個協(xié)議類型在語法上和類型的檢查和轉(zhuǎn)換完全相同:”
//“is 用來檢查實例是否符合某個協(xié)議,若符合則返回 true,否則返回 false?!?br> //“as? 返回一個可選值,當(dāng)實例符合某個協(xié)議時,返回類型為協(xié)議類型的可選值,否則返回 nil?!?br> //“as! 將實例強制向下轉(zhuǎn)換到某個協(xié)議類型,如果強轉(zhuǎn)失敗,會引發(fā)運行時錯誤?!?/p>

protocol HasArea{
    var area:Double {get}
}
class Circle:HasArea{
    let pi = 3.1415926
    var radius : Double
    var area: Double{
        return pi*radius*radius
    }
    init(radius:Double) {
        self.radius = radius
    }
}
class Country: HasArea {
    var area: Double
    init(area:Double) {
        self.area = area
    }
}
class Animal {
    var legs : Int
    init(legs:Int) {
        self.legs = legs
    }
}
let objects : [AnyObject] = [
    Circle(radius:2.0),
    Country(area:243_610),
    Animal(legs:4),
]
for object in objects {
    if let objectWithArea = object as? HasArea {
        print("Area is \(objectWithArea.area)")
    }else{
        print("Something that doesn't habe an area")
    }
}
//打印 Area is 12.5663704
//Area is 243610.0
//Something that doesn't habe an area

//“當(dāng)?shù)龅脑胤?HasArea 協(xié)議時,將 as? 操作符返回的可選值通過可選綁定,綁定到 objectWithArea 常量上。objectWithArea 是 HasArea 協(xié)議類型的實例,因此 area 屬性可以被訪問和打印?!?br> //“objects 數(shù)組中的元素的類型并不會因為強轉(zhuǎn)而丟失類型信息,它們?nèi)匀皇?Circle,Country,Animal 類型。然而,當(dāng)它們被賦值給 objectWithArea 常量時,只被視為 HasArea 類型,因此只有 area 屬性能夠被訪問。”

// 可選的協(xié)議要求
//“協(xié)議可以定義可選要求,遵循協(xié)議的類型可以選擇是否實現(xiàn)這些要求。在協(xié)議中使用 optional 關(guān)鍵字作為前綴來定義可選要求??蛇x要求用在你需要和 Objective-C 打交道的代碼中。協(xié)議和可選要求都必須帶上@objc屬性。標(biāo)記 @objc 特性的協(xié)議只能被繼承自 Objective-C 類的類或者 @objc 類遵循,其他類以及結(jié)構(gòu)體和枚舉均不能遵循這種協(xié)議”
//“使用可選要求時(例如,可選的方法或者屬性),它們的類型會自動變成可選的。比如,一個類型為 (Int) -> String 的方法會變成 ((Int) -> String)?。需要注意的是整個函數(shù)類型是可選的,而不是函數(shù)的返回值”
//“協(xié)議中的可選要求可通過可選鏈?zhǔn)秸{(diào)用來使用,因為遵循協(xié)議的類型可能沒有實現(xiàn)這些可選要求。類似 someOptionalMethod?(someArgument) 這樣,你可以在可選方法名稱后加上 ? 來調(diào)用可選方法”

@objc protocol CounterDataSource{
    @objc optional func incrementForCount(count:Int)->Int
    @objc optional var fixedIncrement:Int {get}
}
class Counter {
    var count = 0
    var dataSourece : CounterDataSource?
    func increment(){
        if let amount = dataSourece?.incrementForCount?(count: count) {
            count += amount
        }else if let amount = dataSourece?.fixedIncrement{
            count += amount
        }
    }
}

//“這里使用了兩層可選鏈?zhǔn)秸{(diào)用。首先,由于 dataSource 可能為 nil,因此在 dataSource 后邊加上了 ?,以此表明只在 dataSource 非空時才去調(diào)用 increment(forCount:) 方法。其次,即使 dataSource 存在,也無法保證其是否實現(xiàn)了 increment(forCount:) 方法,因為這個方法是可選的。因此,increment(forCount:) 方法同樣使用可選鏈?zhǔn)秸{(diào)用進行調(diào)用,只有在該方法被實現(xiàn)的情況下才能調(diào)用它,所以在 increment(forCount:) 方法后邊也加上了 ??!?/p>

class ThreeSource: NSObject,CounterDataSource{
    let fixedIncrement = 3
}
var counter = Counter()
counter.dataSourece=ThreeSource()
for _ in 1...4{
    counter.increment()
    print(counter.count)
}
//打印 3
//6
//9
//12
@objc class TowardsZeroSource:NSObject,CounterDataSource{
    func incrementForCount(count: Int) -> Int {
        if count == 0 {
            return 0
        }else if count < 0 {
            return 1
        }else {
            return -1
        }
    }
}
counter.count = -4
counter.dataSourece = TowardsZeroSource()
for _ in 1...5{
    counter.increment()
    print(counter.count)
}
//打印-3
//-2
//-1
//0
//0

//13.協(xié)議擴展
//“協(xié)議可以通過擴展來為遵循協(xié)議的類型提供屬性、方法以及下標(biāo)的實現(xiàn)。通過這種方式,你可以基于協(xié)議本身來實現(xiàn)這些功能,而無需在每個遵循協(xié)議的類型中都重復(fù)同樣的實現(xiàn),也無需使用全局函數(shù)?!?/p>

extension RandomNumberGennerator {
    func randomBool() -> Bool {
        return random() > 0.5
    }
}

//“通過協(xié)議擴展,所有遵循協(xié)議的類型,都能自動獲得這個擴展所增加的方法實現(xiàn),無需任何額外修改:”

let generator = LinearCongruentialGenerator()
print("here si a random Number: \(generator.random())")
//打印 here si a random Number: 0.37464991998171
print("and here is a random boolean:\(generator.randomBool())")
//打印 and here is a random boolean:true

//13.1 提供默認(rèn)實現(xiàn)
// “可以通過協(xié)議擴展來為協(xié)議要求的屬性、方法以及下標(biāo)提供 默認(rèn)的實現(xiàn) 。如果遵循協(xié)議的類型為這些要求提供了自己的實現(xiàn),那么這些自定義實現(xiàn)將會替代擴展中的默認(rèn)實現(xiàn)被使用?!?br> //“注意 通過協(xié)議擴展為協(xié)議要求提供的默認(rèn)實現(xiàn)和可選的協(xié)議要求不同。雖然在這兩種情況下,遵循協(xié)議的類型都無需自己實現(xiàn)這些要求,但是通過擴展提供的默認(rèn)實現(xiàn)可以直接調(diào)用,而無需使用可選鏈?zhǔn)秸{(diào)用。

extension PrettyTextRepresentable{
    var prettyTextualDescrition : String{
        return textualDescription
    }
}

//13.2 為協(xié)議擴展添加限制條件
//“在擴展協(xié)議的時候,可以指定一些限制條件,只有遵循協(xié)議的類型滿足這些限制條件時,才能獲得協(xié)議擴展提供的默認(rèn)實現(xiàn)。這些限制條件寫在協(xié)議名之后,使用 where 子句來描述,正如Where子句中所描述的”

//“例如,你可以擴展 CollectionType 協(xié)議,但是只適用于集合中的元素遵循了 TextRepresentable 協(xié)議的情況”

//extension Collection  where Generator.Element : TextReprresentable{
//    var textualDescription : String{
//        let itemsAsText = self.map{$0.textualDescription}
//        return "[" + itemsAsText.joinWithSeparator(",") + "]"
//    }
//}
//Array
//let murrayTheHamster = Hamster(name:"Murray")
//let morgenTheHamster = Hamster(name:"Morgan")
//let hamsters = [murrayTheHamster,morgenTheHamster]
//print(hamsters.textualDescription)
//應(yīng)該打印“[A hamster named Murray, A hamster named Morgan]” 但是這里一直走不通
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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