Contents
Chào bạn, chúng ta lại tiếp tục seri Lập trình iOS cho mọi người. Bài viết này sẽ nói về Protocol trong Swift. Tìm hiểu về lý thuyết và ứng dụng trong việc coding. Còn nếu bạn chưa biết gì về Swift thì có thể tham khảo bài sau:
Chuẩn bị
- MacOS 10.14.4
- Xcode 11.0
- Swift 5.1
1. Định nghĩa
Protocol dịch ra đầy đủ và đúng nghĩa thì là
giao thức
.(Theo Google Translate)
Tới đây thì bạn sẽ ít nhiều đã hiểu về Protocol rồi. Nó xuất hiện khá nhiều trong đời sống hằng ngày của chúng ta mà không hề hay biết. Hơi ngoài lề một chút, giờ chúng ta đi vào chuyện lập trình thôi.
-
Protocol
- Là một kiểu interface
- Mang tính chất trừu tượng
- Khai báo các properties và các methods
- Không định nghĩa chúng
- Implement được vào class/struct/enum
- Implement được vào nhiều chứ không phải một
- Có thể xem như là 1 kiểu dữ liệu
Tới đây cũng là khá đủ rồi, bắt đầu code thôi!
2. Cú pháp
- Từ khoá:
protocol
protocol SomeProtocol { // protocol definition goes here }
- Implement
- Struct
struct SomeStructure: FirstProtocol, AnotherProtocol { // structure definition goes here }
-
- Class
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { // class definition goes here }
- Việc Implement thì cũng được xem là một hình thức
đa kế thừa
để tăng cường sức mạnh cho class/struct. - Khi class/struct implement một protocol nào đó thì các phương thức và thuộc tính của protocol phải được định nghĩa lại ở class/struct đó
// Protocol protocol P { func show() func add(a: Int, b: Int) -> Int } // A class class A: P { func show() { // code here } func add(a: Int, b: Int) -> Int { // code here return 0 } } // B class class B: P { func show() { // code here } func add(a: Int, b: Int) -> Int { // code here return 0 } }
3. Property
- Với Protocol thì chúng ta có thể khai báo được các thuộc tính.
- Đây là một điểm mạnh của ngôn ngữ Swift
- Xem ví dụ sau:
protocol SomeProtocol { var mustBeSettable: Int { get set } var doesNotNeedToBeSettable: Int { get } } protocol AnotherProtocol { static var someTypeProperty: Int { get set } }
- Ta thấy được một số điều như sau:
- Property có thể là
- Store Property
- Computed Property
- Static hay Non-Static
get
chỉ lấy giá trịget set
vừa lấy vừa ghi được giá trị
- Property có thể là
- Sử dụng trong struct
- Với biến
fullName
vớiget
- Với biến
protocol FullyNamed { var fullName: String { get } } struct Person: FullyNamed { var fullName: String } let john = Person(fullName: "John Appleseed")
- Sử dụng trong class
- Khi thuộc tính chỉ có
get
thì phải định nghĩa lại biến đó rõ ràng hơn thànhreadonly
- Khi thuộc tính chỉ có
class Starship: FullyNamed { var prefix: String? var name: String init(name: String, prefix: String? = nil) { self.name = name self.prefix = prefix } var fullName: String { return (prefix != nil ? prefix! + " " : "") + name } } var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
4. Method
- Khai báo phương thức trong protocol tương tự khai báo hàm thông thường, nhưng không cài đặt.
- Việc cài đặt các phương thức này sẽ được class/struct/enum nào áp dụng thực hiện.
- Ngoài ra, protocol cũng cho phép khai báo phương thức mutating để hỗ trợ người dùng thực hiện việc thay đổi giá trị nội tại của class/struct/enum thực thi protocol.
Ví dụ:
protocol SomeProtocol { static func someTypeMethod() } protocol RandomNumberGenerator { func random() -> Double }
5. Mutating Method
Mutabling method trong protocol nghĩa là cho phép method đó thay đổi thuộc tính nội tại (instance property) của Struct hoặc Enum mà adopt protocol đó.
Phần này thì các bạn nên đọc về Struct và Enum. Vì tụi nó là kiểu tham trị. Còn sau đây là ví dụ đơn giản:
protocol Togglable { mutating func toggle() } enum OnOffSwitch: Togglable { case off, on mutating func toggle() { switch self { case .off: self = .on case .on: self = .off } } } var lightSwitch = OnOffSwitch.off lightSwitch.toggle() // lightSwitch is now equal to .on
6. Init Method
- Với Class/Struct/Enum thì có hàm khởi tạo
init()
để khởi tạo giá trị cho đối tượng đó. - Với Protocol thì cũng có hàm khởi tạo
init
nhưng là để các Class/Struct/Enum nào mà implement nó thì phải bắt buộc có hàm khởi tạo này. - Từ khoá sẽ dùng là
required
- Ví dụ:
protocol SomeProtocol { init() } class SomeSuperClass { init() { // initializer implementation goes here } } class SomeSubClass: SomeSuperClass, SomeProtocol { // "required" from SomeProtocol conformance; "override" from SomeSuperClass required override init() { // initializer implementation goes here } }
Giờ thì nhiều bạn sẽ hiểu ra vì sao khi custom view mà tạo sub-class của UIView lại bị bắt cần có mấy cái function
init
với từ khoárequired
ở trước nữa.
class MyView:UIView { init() {} // Chỗ này bắt buộc nếu ta có viết lại init(), XCode sẽ nhắc và tự thêm như sau required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
7. Class only
Cái tên đã nói lên tất cả rồi.
Khi ta khai báo 1 protocol và kế thừa từ class
thì protocol đó sẽ dùng cho mỗi các Class. Còn Struct và Enum thì không dùng được.
- Mục đích to lớn của nó là gì?
- Tạo
delegate
&datasource
- khai báo với từ khoá
weak
- hạn chế leak bộ nhớ
- Tạo
protocol ForClassProtocol: class { func test() } class TestClass: ForClassProtocol { func test() {} } class TestAnotherClass { weak var delegate: ForClassProtocol? }
8. Optional Protocol
Có 1 câu hỏi: “Protocol có 100 function được khai báo. Và chúng ta khi implement thì phải định nghĩa lại 100 function đó hay sao? Trong khi nhiều function lại không cần dùng tới.”
Điều này thì hay gặp trong UITableviewDelegate
hay UICollectionViewDelegate
, bạn chỉ cần khai báo lại một vài function quan trọng. Còn trong khi có nhiều function khác có cũng được hay không có cũng không sao.
Giải quyết điều này, thì người tiền nhiệm của Swift là Objective-C làm việc này rất tốt. Việc của bạn sẽ là:
- Bước 1: thêm từ khoá
@objc
để khai báoprotocol
đó xài được với code Objective-C - Bước 2: Thêm từ khoá
optional
trước function nào mà bạn mong muốn là không cần định nghĩa lại thì vẫn được. - Ví dụ:
@objc protocol P { func show() func add(a: Int, b: Int) -> Int @objc optional func sum(array: [Int]) -> Int } class A: P { func show() { // code here } func add(a: Int, b: Int) -> Int { // code here return 0 } } class B: P { func show() { // code here } func add(a: Int, b: Int) -> Int { // code here return 0 } func sum(array: [Int]) -> Int { return 0 } }
9. Extension
Để sử dụng Protocol một cách chuyên nghiệp hơn thì lời khuyên của mình dành cho bạn là: “nên tạo extension cho class/struct/enum đó và implement protocol.”
Vì 1 class có thểm implement rất nhiều protocol và chúng nó có thể trùng tên với nhau hoặc bạn sẽ không phân biệt được function nào của protocol nào.
@objc protocol P { func show() func add(a: Int, b: Int) -> Int @objc optional func sum(array: [Int]) -> Int } class C { var a: Int var b: Int var result: Int = 0 init(a: Int, b: Int) { self.a = a self.b = b } } extension C: P { func show() { print("result: \(result)") } func add(a: Int, b: Int) -> Int { return a + b } }
Tới đây thì sang phần kết được rồi. Rất nhiều thứ đã được học.
Tạm kết
- Tìm hiểu về Protocol
- Khai báo và sử dụng Protocol
- Các tính chất, đặc trưng của thuộc tính và phương thức trong Protocol
- Các lưu ý về khởi tạo và class
- Cách implement Protocol hiệu quả với Extension
Related Posts:
Written by chuotfx
Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!
2 comments
Leave a Reply Cancel reply
Fan page
Tags
Recent Posts
- Charles Proxy – Phần 1 : Giới thiệu, cài đặt và cấu hình
- Complete Concurrency với Swift 6
- 300 Bài code thiếu nhi bằng Python – Ebook
- Builder Pattern trong 10 phút
- Observer Pattern trong 10 phút
- Memento Pattern trong 10 phút
- Strategy Pattern trong 10 phút
- Automatic Reference Counting (ARC) trong 10 phút
- Autoresizing Masks trong 10 phút
- Regular Expression (Regex) trong Swift
You may also like:
Archives
- September 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (4)
- April 2024 (2)
- March 2024 (5)
- January 2024 (4)
- February 2023 (1)
- January 2023 (2)
- November 2022 (2)
- October 2022 (1)
- September 2022 (5)
- August 2022 (6)
- July 2022 (7)
- June 2022 (8)
- May 2022 (5)
- April 2022 (1)
- March 2022 (3)
- February 2022 (5)
- January 2022 (4)
- December 2021 (6)
- November 2021 (8)
- October 2021 (8)
- September 2021 (8)
- August 2021 (8)
- July 2021 (9)
- June 2021 (8)
- May 2021 (7)
- April 2021 (11)
- March 2021 (12)
- February 2021 (3)
- January 2021 (3)
- December 2020 (3)
- November 2020 (9)
- October 2020 (7)
- September 2020 (17)
- August 2020 (1)
- July 2020 (3)
- June 2020 (1)
- May 2020 (2)
- April 2020 (3)
- March 2020 (20)
- February 2020 (5)
- January 2020 (2)
- December 2019 (12)
- November 2019 (12)
- October 2019 (19)
- September 2019 (17)
- August 2019 (10)