> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/ios/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/ios/swift/type/category/protocol/protocol-extensions.md).

# Protocol Extensions

{% tabs %}
{% tab title="✅ 可以做" %}

* provide <mark style="color:green;">**default implementations**</mark>. (<mark style="color:red;">**dynamic**</mark> method dispatch)  👉 📗 [參考](https://www.rightpoint.com/rplabs/switch-method-dispatch-table)
* add <mark style="color:green;">**new functionalities**</mark>: (<mark style="color:red;">**static**</mark> method dispatch)
  * add **methods**
  * add (convenience) **initializers** (but <mark style="color:red;">**not**</mark> <mark style="color:purple;">**convenience override init**</mark>)
  * add **subscripts**
  * add **computed properties**
* make existing types <mark style="color:green;">**conform to protocol**</mark>**.**
  {% endtab %}

{% tab title="⛔ 不能做" %}

* <mark style="color:red;">**cannot**</mark> extend/<mark style="color:red;">**inherit**</mark> from another <mark style="color:orange;">**protocol**</mark>. (<mark style="color:purple;">**protocol inheritance**</mark> is always specified in the <mark style="color:purple;">**protocol definition**</mark>. :point\_right: Swift ⟩ [Protocol Extensions](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID521))
* <mark style="color:red;">**cannot**</mark> add <mark style="color:red;">**stored properties**</mark>.
* <mark style="color:red;">**cannot**</mark> add <mark style="color:red;">**property observers**</mark>.
* <mark style="color:red;">**cannot**</mark> add <mark style="color:red;">**designated init**</mark> or <mark style="color:red;">**deinit**</mark> to a class.
* <mark style="color:red;">**cannot**</mark> <mark style="color:purple;">**override**</mark>. (⛔ overriding declarations in extensions is not supported)
  {% endtab %}

{% tab title="📘 手冊" %}

* Swift ⟩&#x20;
  * [Extensions](https://docs.swift.org/swift-book/LanguageGuide/Extensions.html)
  * [Protocol Extensions](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID521)
  * [Nested Types](https://docs.swift.org/swift-book/LanguageGuide/NestedTypes.html)
  * [Nested Types](https://docs.swift.org/swift-book/LanguageGuide/Extensions.html#ID157) in Extensions
    {% endtab %}

{% tab title="📗 參考" %}

* [x] Hacking with Swift ⟩ [Swift Protocols: Tips and Tricks](https://www.hackingwithswift.com/articles/138/swift-protocols-tips-and-tricks)
* [x] Dmitrii Ivanov ⟩ [Protocol extensions](https://dmtopolog.com/protocol-extensions/)
* [ ] RightPoint ⟩ [Method Dispatch in Swift](https://www.rightpoint.com/rplabs/switch-method-dispatch-table)  ⭐️
* [ ] Ole Begemann ⟩ [Method Dispatch in Protocol Extensions](https://oleb.net/blog/2016/06/lily-ballard-swift-dispatch/)
  {% endtab %}

{% tab title="🗣 討論" %}

* [Nested types in protocols (and nesting protocols in types)](https://forums.swift.org/t/nested-types-in-protocols-and-nesting-protocols-in-types/4291)
  {% endtab %}
  {% endtabs %}

{% hint style="warning" %}
問：**protocol extension** 裡面可以加 <mark style="color:red;">**nested types**</mark> 嗎？

答：目前看來不行❗️ (:point\_right: 🗣 [討論](https://forums.swift.org/t/nested-types-in-protocols-and-nesting-protocols-in-types/4291))

[Extensions](https://docs.swift.org/swift-book/LanguageGuide/Extensions.html) can add new <mark style="color:red;">**nested types**</mark> to existing <mark style="color:purple;">**class**</mark>, <mark style="color:purple;">**struct**</mark>, and <mark style="color:purple;">**enum**</mark>.\
(but <mark style="color:red;">**not protocol extensions**</mark>:question:) :point\_right:[Nested Types](https://docs.swift.org/swift-book/LanguageGuide/Extensions.html#ID157) in Extensions
{% endhint %}

## Protocol Definition vs. Protocol Extension

{% hint style="info" %}

* Declaring a method inside the <mark style="color:red;">**protocol (definition)**</mark> creates an *<mark style="color:purple;">**extension point**</mark>* – a method that we **encourage** <mark style="color:orange;">**conforming types**</mark> to <mark style="color:red;">**override**</mark>.&#x20;
* If we put methods into the <mark style="color:red;">**protocol extension**</mark> but *<mark style="color:red;">**not**</mark>* the <mark style="color:red;">**protocol definition**</mark>, all conforming types **still get the method**, except now we’re making it <mark style="color:red;">**harder**</mark> for them to <mark style="color:red;">**override**</mark>. (💈例二)
  {% endhint %}

{% tabs %}
{% tab title="🔸 definition" %}

* define <mark style="color:red;">**requirements**</mark> for **conforming types**. (💈例一)
  {% endtab %}

{% tab title="🌀 extension" %}

* provide <mark style="color:red;">**default implementations**</mark> for protocol requirements. (💈例一)
* provide <mark style="color:red;">**default values**</mark>. (💈例一)
  {% endtab %}

{% tab title="💈例一" %}

```swift
// 🔸 protocol definition
protocol Logging {
    func log(_ message: String)     // method requirement
    var filename: String { get }    // property requirement
}

// 🌀 protocol extension
extension Logging {
    // ⭐ default implementation
    func log(_ message: String) {
        print("\(Date()): \(message).")
    }
    // ⭐ default value
    var filename: String { return "app.log" }
}
```

{% endtab %}

{% tab title="💈例二" %}
:point\_right:[replit](https://replit.com/@pegasusroe/protocol-extension-methods#main.swift)

```swift
// 🔸 protocol definition
protocol Developer {}

// 🌀 protocol extension
extension Developer {
    // ⭐ added in extension but not in definition
    func attendMeeting() { print("OK, let's go!") }
}

// 📦 conforming type
struct SeniorDeveloper: Developer {
    func attendMeeting() { print("No way!") }
}

// ⭐ protocol extension method is called
let dev: Developer = SeniorDeveloper()
dev.attendMeeting()       // ⭐ "OK, let's go!"❗

// ⭐ instance method is called
let david = SeniorDeveloper()
david.attendMeeting()           // ⭐ "No way!"
```

{% endtab %}
{% endtabs %}

## Conditional Protocol Extensions

{% tabs %}
{% tab title="💈範例" %}

```swift
//                   ╭───── condition ──────╮
extension Collection where Element: Equatable {
    func allEqual() -> Bool {
        for element in self {
            if element != self.first { return false }
        }
        return true
    }
}

// test run
let numbers = [100, 100, 100, 100, 100]
numbers.allEqual()    // true
```

{% endtab %}

{% tab title="📘 手冊" %}

* Swift ⟩ [Protocol Extensions](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID521) ⟩ Adding Constraints to Protocol Extensions
  {% endtab %}
  {% endtabs %}
