# Protocol

Protocol เป็นเหมือนพิมพ์เขียวที่ระบุข้อกำหนดต่าง ๆ สำหรับการทำงานหนึ่ง ๆ เช่น ระบุ method ที่ต้องใช้ หรือ properties ที่จำเป็น

ผู้ที่ implement การทำงานของพิมพ์เขียวเป็นได้ทั้ง Class, Struct หรือ Enum เราจะเรียก type ที่ทำงานได้ตามพิมพ์เขียวนี้ว่า type นี้ conform protocol

การประกาศใช้ เริ่มด้วย `protocol` จากนั้นคือชื่อของ protocol ตามด้วยข้อกำหนดของ protocol

```swift
protocol SomeProtocol {
    // protocol definition goes here
}
```

เช่น

```swift
protocol ItemDiscribable {
    var description: String { get }
}
protocol Togglable {
    mutating func toggle()
}
```

การประกาศว่า conform protocol ใช้ `:` หลังชื่อของ Struct, Enum หรือ Class แล้วตามด้วย ชื่อของ protocol ที่เราต้องการ conform ซึ่งเราอาจ conform ได้มากกว่าหนึ่งอัน&#x20;

```swift
struct SomeStructure: FirstProtocol, AnotherProtocol {
    // structure definition goes here
}
enum SomeEnum: FirstProtocol {
    // enum definition goes here
}
```

สำหรับ class ที่ต้องการ interit จาก class อื่น เนื่องจากการ inherit สามารถทำได้จาก parent เดียว จึงให้ใส่ชื่อ class นั้นก่อน แล้วจึงตามด้วย protocol

```swift
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
    // class definition goes here
}
```

{% hint style="info" %}
Swift เน้นแนวความคิดแบบ protocol oriented programming โดยการเอา protocol หลาย ๆ อัน มา composition กัน มากว่าแนวลึกแบบ object oriented programming&#x20;

ดูเพิ่มเติมได้ที่ [Protocol-Oriented Programming](https://developer.apple.com/videos/play/wwdc2015/408/)
{% endhint %}

ตัวอย่างการ conform protocol จาก TapSwitch ที่เราเขียนกันไปก่อนหน้านี้ เนื่องจากเรา implement ของที่ protocol เราต้องการอยู่แล้ว เราจึงแค่ใส่ชื่อ protocol เพิ่มในการประกาศ Enum

```swift
enum TapSwitch: ItemDiscribable, Togglable {
    case on
    case off

    var description: String {
        switch self {
        case .on: return "current is on"
        case .off: return "current is off"
        }
    }

    mutating func toggle() {
        switch self {
        case .on:
            self = .off
        case .off:
            self = .on
        }
    }
}

let state = TapSwitch.on
print(state)
```

ทำให้เราสามารถสร้าง Array เป็น type ของ protocol และเก็บของที่ต่างกันไว้รวมกันได้

```swift
class Item: ItemDiscribable {
    var name: String
    var isDone: Bool

    var description: String {
        return name
    }

    init(name: String, isDone: Bool) {
        self.name = name
        self.isDone = isDone
    }
}

let items: [ItemDiscribable] = [Item(name: "Test", isDone: false), TapSwitch.off]
for item in items {
    print(item)
}
```

{% hint style="info" %}
เราสามารถเช็ค Type ของตัวแปรได้ว่าเป็น Type นั้นหรือเปล่าด้วย `is`&#x20;

```swift
if item is Item {
    print("item is Item")
}
```

เราสามารถ cast type ได้ด้วย `as?` และ `as!` และเช่นเดิม การ cast ด้วย `as?` จะได้ optional เราจึงใช้ optional binding ร่วมด้วย ส่วน `as!` เป็นการ force-unwrap ซึ่งจะไม่ได้ optional และถ้าค่านั้นเป็น `nil` โปรแกรมจะ crash

```swift
if let item = item as? Item {
    print(item.isDone)
}
```

{% endhint %}

{% hint style="info" %}
บางครั้งเราสามารถสร้าง Type ใหม่โดยการเอามารวมกันแบบนี้

```swift
typealias Codable = Decodable & Encodable
```

{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pakornpat.gitbook.io/ios-app/v2/swift/protocol.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
