swift 學(xué)習(xí)(10)Protocols

There’s one final type that can bridge common behaviors between structs, classes and enums. In fact, it is itself a user-defined named type: the protocol.
A protocol can be adopted by a class, struct, or enum — and when another type adopts a protocol, it’s required to implement the methods and properties defined in the protocol. Once a type implements all members of a protocol, the type is said to conform to the protocol.
協(xié)議可以由類,結(jié)構(gòu)或枚舉采用 - 當(dāng)另一種類型采用協(xié)議時,需要實(shí)現(xiàn)協(xié)議中定義的方法和屬性。 一旦類型實(shí)現(xiàn)了協(xié)議的所有成員,那么該類型被認(rèn)為符合協(xié)議。

Methods in protocols

在協(xié)議中定義的方法都不需要實(shí)現(xiàn)。

enum Direction {
  case left
  case right
}
protocol DirectionalVehicle {
  func accelerate()
  func stop()
  func turn(direction: Direction)
  func description() -> String
}

Properties in protocols

在協(xié)議中聲明的屬性,需要明確的標(biāo)記是get 或者 get 和 set。
協(xié)議中定義的屬性,協(xié)議本身并不關(guān)心具體如何實(shí)現(xiàn),你可以使用計(jì)算屬性實(shí)現(xiàn)、也可以使用存儲屬性存儲。所有的協(xié)議定義屬性都要明確要求屬性是只讀還是 讀與寫。

protocol Account {
    var value: Double { get set }
    init(initialAmount: Double)
    init?(transferAccount: Account)
}

class BitcoinAccount: Account {
    var value: Double
    required init(initialAmount: Double) {
        value = initialAmount
    }
    required init?(transferAccount: Account) {
        guard transferAccount.value > 0.0 else {
            return nil
        }
        value = transferAccount.value
    }
}
var accountType: Account.Type = BitcoinAccount.self
let account = accountType.init(initialAmount: 30.00)

Protocol inheritance

協(xié)議定義時可以繼承自其他的協(xié)議。

Implementing protocols

protocol Vehicle {
    func accelerate()
    func stop()
}
class Bike: Vehicle {
    var peddling = false
    var brakesApplied = false
    func accelerate() {
        peddling = true
        brakesApplied = false
    }
    func stop() {
        peddling = false
        brakesApplied = true
    }
}

Associated types in protocols

protocol WeightCalculatable {
    associatedtype WeightType
    func calculateWeight() -> WeightType
}


class HeavyThing: WeightCalculatable {
    // This heavy thing only needs integer accuracy
    typealias WeightType = Int
    func calculateWeight() -> Int {
        return 100
    }
}

class LightThing: WeightCalculatable {
    // This light thing needs decimal places
    typealias WeightType = Double
    func calculateWeight() -> Double {
        return 0.0025
    }
}

因?yàn)閟wift 具有類型推導(dǎo),所有上面的 typealias WeightType 可以不寫,直接使用。

Implementing multiple protocols

每個類只能繼承自一個類,但是它可以遵守多個協(xié)議。

class Bike: Vehicle, Wheeled {
  // Implement both Vehicle and Wheeled
}

類也可以使用擴(kuò)展接收協(xié)議。這樣就很好的實(shí)現(xiàn)了代碼分離。

class Bike {
    var wheelNumber : String = ""
    var wheelSize = 0.0
    init(wheelNumber:String,wheelSize:Double) {
        self.wheelSize = wheelSize
        self.wheelNumber = wheelNumber
    }
}

extension Bike : Hashable
{
    var hashValue: Int {
        return self.wheelNumber.hashValue
    }
}
extension Bike : CustomStringConvertible
{
    
    var description: String {
        return "\(self.wheelNumber) "
    }
}

Requiring reference semantics

Protocols can be adopted by both value types (structs and enums) and reference types (classes), so you might wonder if protocols have reference or value semantics.
協(xié)議可以由兩種值類型(結(jié)構(gòu)和枚舉)和引用類型(類)采用,因此您可能想知道協(xié)議是否具有引用或值語義。

protocol Named {
    var name: String { get set }
}
class ClassyName: Named {
    var name: String
    init(name: String) {
        self.name = name
    }
}
struct StructyName: Named {
    var name: String
}

//指針指向同一塊內(nèi)存地址。
var named: Named = ClassyName(name: "Classy")
var copy = named
named.name = "Still Classy"
named.name // Still Classy
copy.name // Still Classy

//值COPY
named = StructyName(name: "Structy")
copy = named
named.name = "Still Structy?"
named.name // Still Structy?
copy.name // Structy

容易引起歧義。如果我們設(shè)計(jì)了一個專門讓類引用的協(xié)議,可以在聲明協(xié)議時加一個關(guān)鍵字

protocol Named: class {
  var name: String { get set }
}

這樣就只有類可以引用該協(xié)議。

Protocols in the standard library

The Swift standard library uses protocols extensively in ways that may surprise you. Understanding the roles protocols play in Swift can help you write clean, decoupled “Swifty” code.

Equatable

如果是兩個int類型常量 或者 stirng 類型的常量 的可以直接使用 == 進(jìn)行比較操作的。但是struct 類型就不能直接使用 == 進(jìn)行比較。

這是因?yàn)镮nt 和 String 引用了 Equatable 協(xié)議。
如何struct 也想使用 == 操作符,引用 Equatable 就行了。

struct Record {
  var wins: Int
  var losses: Int
}

extension Record: Equatable {
  static func ==(lhs: Record, rhs: Record) -> Bool                                  
    {   
        return lhs.wins == rhs.wins &&
             lhs.losses == rhs.losses
    } 
}

let recordA = Record(wins: 10, losses: 5)
let recordB = Record(wins: 10, losses: 5)
recordA == recordB // true

Key points

  • Protocols define a contract classes, structs and enums can adopt.協(xié)議定義了一個契約類,結(jié)構(gòu)體和枚舉可以采用。
  • By adopting a protocol, a type is required to conform to the protocol by implementing all methods and properties of the protocol.采用協(xié)議,需要實(shí)現(xiàn)協(xié)議的所有方法和屬性來遵循協(xié)議的類型。
  • A type can adopt any number of protocols, which allows for a quasi-multiple inheritance not permitted through subclassing.數(shù)據(jù)可以通過使用多個協(xié)議來達(dá)到多繼承的效果。
  • You can use extensions for protocol adoption and conformance.
  • The Swift standard library uses protocols extensively(大量的). You can use many of them, such as Equatable and Hashable, on your own named types.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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