about 6 years ago

Protocols 提出 methods, property 等等的需求,本身不需要實作,
實作交由實際要滿足這些要求的對象。

基本宣告與實作對象

protocol MyProtocol {
}
class MyClass: MyProtocol {
}

若有繼承,要將 protocol 放在 superclass 後面。

protocol MyProtocol {
}
class MyClass {
}
class MyClass2: MyClass, MyProtocol {
}

Property 需求

定義 property 時必須要加上 get, set,若是 readonly,只需加上 get。

protocol MyProtocol {
    var pro: Int { get set }
    var pro2: String { get }
}
class MyClass: MyProtocol {
    var pro: Int {
    get {
        return 123
    }
    set {
        print(newValue)
    }
  }
  var pro2: String {
        return "123"
  }
}

Methods 需求

protocol MyProtocol {
    func myFunc() {
    }
}
class MyClass: MyProtocol {
    func myFunc() {
        print("func")
    }
}

若有其他類型的 method,例如 static 或是 mutating,必須在 protocol 先定義。

protocol MyProtocol {
    static func myFunc() {
    }
    mutating func myFunc(para: int) {
    }
}
class MyClass: MyProtocol {
    static func myFunc() {
    }
    func myFunc(para: Int) {
    }
}

Initializer 需求

在 protocol 可以定義 designated initializer 或是 convenience initializer,
實作對象都必須要加上 required,除非 class 被定義為 final。

protocol MyProtocol {
    init(para: Int)
}

class MyClass: MyProtocol {
    required init(para: Int) {
    }
}
final MyClass: MyProtocol {
    init(para: Int) {
    }
}

Protocol 類型

Protocol 可以被當作類型,因此可以當作 function 的參數類型或是 array 的 value 類型,
符合 protocol 類型的就是實作的類別。

protocol MyProtocol {
    func test()
}
class MyClass: MyProtocol {
    func test() {
        print("class")
    }
}
class MyClass2: MyProtocol {
    func test() {
        print("class")
    }
}
func myFunc(para: MyProtocol) {
    para.test()
}
myFunc(para: MyClass())
let array: [MyProtocol] = [MyClass(), MyClass2()]

Delegation

可以使用 protocol 來實現 delegation 的 design pattern。

protocol MyProtocol {
    func willStart()
    func didStart()
    func endStart()
}
class MyClass {
    var delegate: MyProtocol?
  func myFunc() {
        delegate?.willStart()
    }
}
class MyClass2: MyProtocol {
    func willStart() {
    }
  func didStart() {
    }
  func endStart() {
    }
}
let c = MyClass()
c.delegate = MyClass2()

With Extension

可以在 extension 內實作 protocol。

protocol MyProtocol {
}
class MyClass {
}
extension MyClass: MyProtocol {
}

若類別裡面已經實作了 protocol 的需求,可以在 extension 加上空實作。

protocol MyProtocol {
    func myFunc()
}
class MyClass {
    func myFunc() {
  }
}
extension MyClass: MyProtocol {}

繼承 Protocol

Protocol 之間可以互相繼承。

protocol MyProtocol {
    func myFunc()
}
protocol MyProtocol2: MyProtocol {
}
class MyClass: MyProtocol2 {
    func myFunc() {
  }
}

Class only Protocol

定義此 Protocol 只有 classes 能夠使用。

protocol MyProtocol: class {
}

多種 protocol 類型

將 protocol 當作類型時,可以合併多種的 protocol,使用 & 關鍵字。

protocol MyProtocol {
}
protocol MyProtocol2 {
}
class MyClass: MyProtocol, MyProtocol2 {

}
func myFunc(para: MyProtocol & MyProtocol2) {
}
func myFunc(MyClass())

檢查 protocol

使用 is 跟 as 。

protocol MyProtocol {
}
class MyClass {
}
let c = MyClass()
if let result c as? MyProtocol {
}

Optional 要求

在 protocol 內的要求都必須要實作,但也可以宣告 optional 代表不一定要滿足的要求,
但宣告時前面一定要加上 @objc,意思是與 objc 的 class 互通使用,
因此無法使用在 structure 或是 enumeration 上。

@objc protocol MyProtocol {
    @objc func myFunc()
}
class MyClass: MyProtocol {
}

也適用之前提到的 optional chaining。

@objc protocol MyProtocol {
    @objc var pro: Int {get}
}
class MyClass {
    var delegate: MyProtocol?
}
class MyClass2: MyProtocol {
}
let c = MyClass()
c.delegate = MyClass2()
c.delegate?.pro

在 optionals protocol 中定義 property 的時候只能夠宣告 get,無法使用 set。

Protocol extension

額外在 extension 加上實作。

protocol MyProtocol {
    var pro: String { get }
}
extension MyProtocol {
    func myFunc() -> String {
    return pro
  }
}

在 extension 內加上預設實作,若有預設實作,則滿足對象不一定要實作,
若有滿足對象有實作,則會覆蓋掉 extension 預設的實作。

protocol MyProtocol {
    var pro: String { get }
}
extension MyProtocol {
    var pro: String {
    get {
        return "123"
    }
  }
}
class MyClass: MyProtocol {
    var pro: String {
    get {
        return "456"
    }
  }
}
← iOS Swift : Extensions iOS Swift : Generics →