21.協(xié)議 Protocols Swift官方文檔——版納的筆記

//: Playground - noun: a place where people can play

import UIKit

// # 協(xié)議的語(yǔ)法

// # 屬性要求
// 必須定義為變量屬性,因?yàn)樵诙x時(shí)看上去是個(gè)計(jì)算屬性.
protocol AProtocol {
    var mustBeSettable: Int { get set } // 只能是get-set計(jì)算或var存儲(chǔ)屬性
    var canBeSettable: Int { get } // 可以是各類屬性.
    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

// # 方法要求
// 方法參數(shù)不能定義默認(rèn)值
protocol RandomNumberGenerator {
    func random() -> Double
}
// 線性同余法生成偽隨機(jī)數(shù)
class LinearCongruentialGenerator: RandomNumberGenerator {
    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
    }
}
let generator = LinearCongruentialGenerator()
print(generator.random())
print(generator.random())

// # 異變方法要求
protocol Togglable {
    mutating func toggle()
}
enum OnOffSwitch: Togglable {
    case off, on
    mutating func toggle() {
        switch self {
        case .off:
            self = .on
        default:
            self = .off
        }
    }
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle()

// # 初始化器要求
// 可以使用required, final關(guān)鍵字
protocol SomeProtocol {
    init()
}
class SomeSuperClass {
    init() {}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
    required override init() {}
}
// 遵循協(xié)議的類型可以使用一個(gè)可失敗的或不可失敗的初始化器滿足一個(gè)可失敗的初始化器要求。不可失敗初始化器要求可以使用一個(gè)不可失敗初始化器或隱式展開的可失敗初始化器滿足同仆。

// # 將協(xié)議作為類型***
class Dice {
    let sides: Int
    let generator: RandomNumberGenerator
    init(sides: Int, generator: RandomNumberGenerator) {
        self.sides = sides
        self.generator = generator
    }
    func roll() -> Int {
        return Int(generator.random() * Double(sides)) + 1
    }
}
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1...5 {
    print("Random dice roll is \(d6.roll())")
}

// # 委托
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)
}
class SnakesAndLadders: DiceGame {
    let finalSquare = 25
    let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
    var square = 0
    var board: [Int]
    init() {
        board = Array(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)
    }
}
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)-sided 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")
    }
}
let tracker = DiceGameTracker()
let game = SnakesAndLadders()
game.delegate = tracker
game.play()

// # 在擴(kuò)展里添加協(xié)議遵循
// 類型已經(jīng)存在的實(shí)例會(huì)在給它的類型擴(kuò)展中添加遵循協(xié)議時(shí)自動(dòng)地采納和遵循這個(gè)協(xié)議萤捆。
protocol TextRepresentable {
    var textualDescription: String { get }
}
extension Dice: TextRepresentable {
    var textualDescription: String {
        return "A \(sides)-sided dice"
    }
}
let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
print(d12.textualDescription)
extension SnakesAndLadders: TextRepresentable {
    var textualDescription: String {
        return "A game of Snakes and Ladders with \(finalSquare) squares"
    }
}
print(game.textualDescription)
// 如果一個(gè)類型已經(jīng)遵循了協(xié)議的所有需求,但是還沒有聲明它采納了這個(gè)協(xié)議俗批,可以讓通過(guò)一個(gè)空的擴(kuò)展來(lái)讓它采納這個(gè)協(xié)議
struct Hamster {
    var name: String
    var textualDescription: String {
        return "A hamster named \(name)"
    }
}
extension Hamster: TextRepresentable {}
let simonTheHamster = Hamster(name: "Simon")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
print(somethingTextRepresentable.textualDescription)

// # 協(xié)議類型的集合
let things: [TextRepresentable] = [game, d12, simonTheHamster]
for thing in things {
    print(thing.textualDescription)
}

// # 協(xié)議繼承
protocol PrettyTextRepresentable: TextRepresentable {
    var prettyTextualDescription: String { get }
}
extension SnakesAndLadders: PrettyTextRepresentable {
    var prettyTextualDescription: 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
    }
}
print(game.prettyTextualDescription)

// # 類專用的協(xié)議
protocol SomeClassOnlyProtocol: AnyObject {
    // class-only protocol definition goes here.
}
// AnyObject is a protocol to which all classes implicitly conform.

// # 協(xié)議組合
// 用&連接
protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}
struct OnePerson: Named, Aged {
    var name: String
    var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
    print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = OnePerson(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
// 也可以包含一個(gè)父類
class Location {
    var latitude: Double
    var longitude: Double
    init(latitude: Double, longitude: Double) {
        self.latitude = latitude
        self.longitude = longitude
    }
}
class City: Location, Named {
    var name: String
    init(name: String, latitude: Double, longitude: Double) {
        self.name = name
        super.init(latitude: latitude, longitude: longitude)
    }
}
func beginConert(in location: Location & Named) {
    print("Hello, \(location.name)!")
}
let seattle = City(name: "Seattle", latitude: 47.6, longitude: -122.3)
beginConert(in: seattle)

// # 協(xié)議遵循的檢查
protocol HasArea {
    var area: Double { get }
}
class Circle: HasArea {
    let pi = 3.1415927
    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 }
}
// Here is a class does not conform to HasArea protocol.
class Animal {
    var legs: Int
    init(legs: Int) {
        self.legs = legs
    }
}
// But we can put all three of they into an array...
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 have an area")
    }
}

// # 可選協(xié)議要求
// 允許與Objective-C協(xié)作.@objc 協(xié)議只能被繼承自 Objective-C 類或其他 @objc 類采納俗或。它們不能被結(jié)構(gòu)體或者枚舉采納。
@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}
class Counter {
    var count = 0
    var dataSource: CounterDataSource?
    func increment() {
        if let amount = dataSource?.increment?(forCount: count) {
            count += amount // there may or may not be an increment func
        } else if let amount = dataSource?.fixedIncrement {
            count += amount
        }
    }
}
// NSObject means this is an Obj-C class
class ThreeSource: NSObject, CounterDataSource {
    let fixedIncrement: Int = 3
}
var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
    counter.increment()
    print(counter.count)
}
// more complicated one
@objc class TowardsZeroSource: NSObject, CounterDataSource {
    func increment(forCount count: Int) -> Int {
        if count == 0 {
            return 0
        } else if count < 0 {
            return 1
        } else {
            return -1
        }
    }
}
counter.count = -4
counter.dataSource = TowardsZeroSource()
for _ in 1...5 {
    counter.increment()
    print(counter.count)
}

// # 協(xié)議擴(kuò)展
// 為所有遵循協(xié)議的實(shí)現(xiàn)添加擴(kuò)展方法和屬性.
extension RandomNumberGenerator {
    func randomBool() -> Bool {
        return random() > 0.5
    }
}
let generatorA = LinearCongruentialGenerator()
print("Here's a random number: \(generatorA.random())")
print("And here's a random Boolean: \(generatorA.randomBool())")
// 注意:提供的只是默認(rèn)實(shí)現(xiàn).如果遵循類型給這個(gè)協(xié)議的要求提供了它自己的實(shí)現(xiàn)岁忘,那么它就會(huì)替代擴(kuò)展中提供的默認(rèn)實(shí)現(xiàn)辛慰。
extension PrettyTextRepresentable {
    var prettyTextualDescription: String {
        return textualDescription
    }
}
// 給協(xié)議擴(kuò)展添加限制.
// trick: where's implement.
extension Collection where Iterator.Element: TextRepresentable {
    var textualDescription: String {
        // trick: map: returns an array containing the results of mapping the given closure over the sequence’s elements.
        let itemsAsText = self.map { $0.textualDescription }
        // trick: .joined: make them a String
        return "[" + itemsAsText.joined(separator: ", ") + "]"
    }
}
let murrayTheHamster = Hamster(name: "Murray")
let morganTheHamster = Hamster(name: "Morgan")
let mauriceTheHamster = Hamster(name: "Maurice")
let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster]
print(hamsters.textualDescription)

// ***父類服從某協(xié)議,則子類也服從該協(xié)議干像,可以用is探測(cè)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末帅腌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子麻汰,更是在濱河造成了極大的恐慌速客,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件什乙,死亡現(xiàn)場(chǎng)離奇詭異挽封,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門辅愿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)智亮,“玉大人,你說(shuō)我怎么就攤上這事点待±龋” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵癞埠,是天一觀的道長(zhǎng)状原。 經(jīng)常有香客問(wèn)我,道長(zhǎng)苗踪,這世上最難降的妖魔是什么颠区? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮通铲,結(jié)果婚禮上毕莱,老公的妹妹穿的比我還像新娘。我一直安慰自己颅夺,他們只是感情好朋截,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著吧黄,像睡著了一般部服。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拗慨,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天廓八,我揣著相機(jī)與錄音,去河邊找鬼胆描。 笑死瘫想,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的昌讲。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼减噪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼短绸!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起筹裕,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤醋闭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后朝卒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體证逻,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年抗斤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了囚企。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丈咐。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖龙宏,靈堂內(nèi)的尸體忽然破棺而出棵逊,到底是詐尸還是另有隱情,我是刑警寧澤银酗,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布辆影,位于F島的核電站,受9級(jí)特大地震影響黍特,放射性物質(zhì)發(fā)生泄漏蛙讥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一灭衷、第九天 我趴在偏房一處隱蔽的房頂上張望键菱。 院中可真熱鬧,春花似錦今布、人聲如沸经备。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)侵蒙。三九已至,卻和暖如春傅蹂,著一層夾襖步出監(jiān)牢的瞬間纷闺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工份蝴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留犁功,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓婚夫,卻偏偏與公主長(zhǎng)得像浸卦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子案糙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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

  • 0×1.VTP協(xié)議介紹Cisco交換機(jī)一旦通過(guò)某種方式激活了干線(Trunk)限嫌,這些交換機(jī)會(huì)通過(guò)通告報(bào)文來(lái)指示哪些...
    Zero___閱讀 986評(píng)論 0 1
  • Block 注: 將時(shí)機(jī)放到自己成員函數(shù)內(nèi)部奢讨,防止出現(xiàn)循環(huán)引用 CustomView.h文件 CustomView...
    jayck閱讀 139評(píng)論 0 0
  • 《請(qǐng)抓緊年少輕狂的時(shí)光,談一場(chǎng)轟轟烈烈的戀愛吧》 朋友們扒袖,在你們還正當(dāng)風(fēng)華正茂的年紀(jì)的時(shí)候塞茅,請(qǐng)認(rèn)真仔細(xì)的看一下這條...
    千野忍閱讀 461評(píng)論 0 0
  • 兩天的時(shí)間讀完,吳軍博士的《智能時(shí)代》僚稿,發(fā)現(xiàn)我讀了好多人工智能方面的書凡桥,對(duì)于“大數(shù)據(jù)”這個(gè)詞有挺多定義。大數(shù)據(jù)到底...
    聰明的烏龜閱讀 143評(píng)論 0 0
  • 2011年暑假蚀同,我住在上海郊區(qū)的一個(gè)停車場(chǎng)里缅刽,和爸爸媽媽在一起。和隔壁老鄉(xiāng)一家相處得還算不錯(cuò)蠢络。叔叔是個(gè)小包工頭衰猛,長(zhǎng)...
    小丑一人的康橋閱讀 574評(píng)論 16 2