Khái niệm Protocol
Protocol được hiểu là một bản thiết kế bao gồm các thuộc tính, phương thức và các khai báo khác để thực hiện một nhiệm vụ, tính năng nào đó
Protocol có thể được implement bởi một Class, Struct hay Enum.
Khi implement một Protocol, ta sẽ phải khai báo, định nghĩa lại các thuộc tính, phương thức có trong Protocol đó.
Cú pháp khai báo Protocol
Cú pháp khai báo Protocol tương đối giống Class, Struct hay Enum
1 2 3 4 5 | <span class="token comment">// Khai báo Protocol</span> <span class="token keyword">protocol</span> <span class="token builtin">Code</span> <span class="token punctuation">{</span> <span class="token comment">// Nội dung Protocol khai báo trong đây</span> <span class="token punctuation">}</span> |
Muốn Struct, Class hay Enum implement một hoặc nhiều Protocol, ta khai báo như sau
1 2 3 4 5 6 | <span class="token keyword">protocol</span> <span class="token builtin">Eat</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">struct</span> <span class="token builtin">Dev</span><span class="token punctuation">:</span> <span class="token builtin">Code</span><span class="token punctuation">,</span> <span class="token builtin">Eat</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> |
Trường hợp khai báo implement cho một Subclass, ta phải để tên của Superclass (Lớp cha) lên trước tên các Protocol
1 2 3 4 5 6 | <span class="token keyword">class</span> <span class="token class-name">Human</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">Dev</span><span class="token punctuation">:</span> <span class="token builtin">Human</span><span class="token punctuation">,</span> <span class="token builtin">Code</span><span class="token punctuation">,</span> <span class="token builtin">Eat</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> |
Khai báo thuộc tính, phương thức trong Protocol
Thuộc tính trong Protocol
Để khai báo thuộc tính trong Protocol, phải có đủ 3 yếu tố
- Tên thuộc tính
- Kiểu dữ liệu
- Trạng thái của thuộc tính (get – get set)
1 2 3 4 5 | <span class="token keyword">protocol</span> <span class="token builtin">Code</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> experience<span class="token punctuation">:</span> <span class="token builtin">Int</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span> <span class="token keyword">var</span> language<span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Lưu ý: Thuộc tính trong Protocol phải khai báo là một var. Do Protocol mặc định những thuộc tính này ở dạng Computed Properties nên không thể khai báo let và phải khai báo thêm trạng thái get hoặc get set
1 2 3 4 5 6 | <span class="token keyword">protocol</span> <span class="token builtin">Code</span> <span class="token punctuation">{</span> <span class="token keyword">let</span> level<span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span> <span class="token comment">// Error: 'let' declarations cannot be computed properties </span> <span class="token keyword">var</span> experience<span class="token punctuation">:</span> <span class="token builtin">Int</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span> <span class="token keyword">var</span> language<span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Protocol hỗ trợ từ khoá “static” để khai báo thuộc tính thuộc về Type thay vì Instance (Protocol không hỗ trợ từ khoá “class”)
Phương thức trong Protocol
Khai báo phương thức trong Protocol tương tự với Class, Struct nhưng không có dấu {} và không có nội dung.
Protocol hỗ trợ cả Type Function (khai báo “static”) và cả Instance Function
Lưu ý: Protocol không cho phép sử dụng hằng số làm parameter cho phương thức
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">enum</span> <span class="token builtin">FeelHungry</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> yes <span class="token keyword">case</span> no <span class="token punctuation">}</span> <span class="token keyword">protocol</span> <span class="token builtin">Human</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">talk</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">eat</span><span class="token punctuation">(</span><span class="token number">_</span> feelHungry<span class="token punctuation">:</span> <span class="token builtin">FeelHungry</span><span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">eat2</span><span class="token punctuation">(</span><span class="token number">_</span> feelHungry<span class="token punctuation">:</span> <span class="token builtin">FeelHungry</span> <span class="token operator">=</span> <span class="token punctuation">.</span>yes<span class="token punctuation">)</span> <span class="token comment">// Error: Default argument not permitted in protocol method </span> <span class="token punctuation">}</span> |
Nếu Struct hay Enum implement Protocol, mà khi định nghĩa các phương thức, ta muốn thay đổi thuộc tính của nó, ta sẽ phải khai báo thêm từ khoá “mutating” (Do Struct và Enum là kiểu tham trị)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token keyword">protocol</span> <span class="token builtin">Activities</span> <span class="token punctuation">{</span> <span class="token keyword">mutating</span> <span class="token keyword">func</span> <span class="token function">eat</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">enum</span> <span class="token builtin">State</span><span class="token punctuation">:</span> <span class="token builtin">Activities</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> hungry <span class="token keyword">case</span> notHungry <span class="token keyword">mutating</span> <span class="token keyword">func</span> <span class="token function">eat</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> <span class="token keyword">self</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token punctuation">.</span>notHungry<span class="token punctuation">:</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"Don't need to eat"</span><span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span>hungry<span class="token punctuation">:</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token string">"Eat something"</span><span class="token punctuation">)</span> <span class="token keyword">self</span> <span class="token operator">=</span> <span class="token punctuation">.</span>notHungry <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Optional Protocol
Khi một Protocol chứa rất nhiều phương thức mà không muốn các đối tượng implement Protocol đó phải khai báo lại tất cả, ta sử dụng tới Optional Protocol.
Có 2 cách để khai báo Optional Protocol
Cách 1: @objc optional
Khai báo từ khoá @objc optional
trước thuộc tính, phương thức và “@objc” trước khai báo Protocol. Cách khai báo này đưa protocol về trình biên dịch của Objective – C nên chỉ class implement được Protocol này)
1 2 3 4 5 6 7 8 9 10 11 | <span class="token atrule">@objc</span> <span class="token keyword">protocol</span> <span class="token builtin">OptionalMethodsProtocol</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">mustImplement</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token atrule">@objc</span> <span class="token keyword">optional</span> <span class="token keyword">var</span> <span class="token function">haveNotImplement</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">SomeClass</span><span class="token punctuation">:</span> <span class="token builtin">OptionalMethodsProtocol</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">mustImplement</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token comment">// Không cần khai báo lại haveNotImplements() do đó là optional </span> <span class="token punctuation">}</span> |
Cách 2: Extention Protocol
Đây là cách viết optional protocol phù hợp cho cả Struct, Enum lẫn Class.
Lưu ý: Không khai báo được Stored Properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">protocol</span> <span class="token builtin">OptionalProtocol</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">mustImplement</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">extension</span> <span class="token builtin">OptionalProtocol</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">haveNotImplement</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">struct</span> <span class="token builtin">SomeStruct</span><span class="token punctuation">:</span> <span class="token builtin">OptionalProtocol</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">mustImlement</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token comment">// Không cần khai báo lại haveNotImplements() do đó là optional </span> <span class="token punctuation">}</span> |
Ứng dụng của Protocol
- Protocol có thể sử dụng như một kiểu dữ liệu
- Sử dụng trong Delegate Design Pattern (Sử dụng để “bắt sự kiện”, truyền dữ liệu giữa các ViewController”)
- Mở rộng đối tượng
- Sử dụng trong nhiều thư viện tiêu chuẩn của Swift (Equable, Comparable, Hasable, Int, …)
- Lập trình POP (Protocol Oriented Programming)