Mặc dù không có chức năng cụ thể, protocols vẫn có thể được sử dụng giống như các loại khác tương tự. Tức là, ta có thể sử dụng như:
- Parameters
- Return types của 1 function
- Variables
- Constants
- Collections.
protocol Person { var firstName: String {get set} var lastName: String {get set} var birthDate: Date {get set} var profession: String {get} init (firstName: String, lastName: String, birthDate: Date) }
a. Sử dụng như 1 parameter, return type, array hoặc 1 type
func updatePerson(person: Person) -> Person { var newPerson: Person // Code to update person goes here return newPerson }
var personArray = [Person]() var personDict = [String: Person]()
b. Sử dụng bằng tính chất đa hình
var myPerson: Person
myPerson = SwiftProgrammer(firstName: "Jon", lastName: "Hoffman", birthDate: birthDateProgrammer) myPerson = FootballPlayer(firstName: "Dan", lastName: "Marino", birthdate:birthDatePlayer)
c. Hoặc đa hình trong array:
var programmer = SwiftProgrammer(firstName: "Jon", lastName: "Hoffman", birthDate: bDateProgrammer)
var player = FootballPlayer(firstName: "Dan", lastName: "Marino", birthDate: bDatePlayer)
var people: [Person] = [] people.append(programmer) people.append(player)Rất hay phải không ạ?
Như những ví dụ trên, ta thấy tính đa hình rất hiệu quả và phần này ta nên tự suy nghĩ sẽ thấm hơn. Một vài lưu ý quan trọng khác:
Với mảng people trên, bạn không thể truy cập vào property của programmer bởi vì nó không được định nghĩa trong People protocol.
Để truy cập được, bạn cần phải checking và casting. Có keyword quan trọng
- Keyword is: true nếu đúng, false nếu sai
if person is SwiftProgrammer { print("(person.firstName) is a Swift Programmer") }
for person in people where person is SwiftProgrammer { print("(person.firstName) is a Swift Programmer") }
- Keyword as?: trả về type đó nếu đúng và nil nếu sai
if let _ = person as? SwiftProgrammer { print("(person.firstName) is a Swift Programmer") }
Dùng keyword associatedtype để khai báo.
protocol Queue { associatedtype QueueType mutating func addItem(item: QueueType) mutating func getItem() -> QueueType? func count() -> Int }
struct IntQueue: Queue { var items = [Int]() mutating func addItem(item: Int) { items.append(item) } mutating func getItem() -> Int? { if items.count > 0 { return items.remove(at: 0) } else { return nil } } func count() -> Int { return items.count } }
Tronng ví dụ trên, ta đã implemented Queue protocol theo cách non-generic. Generics cho phép ta sử dụng tại run time thay vì compile time.
- run time là có thể apply generic, tức là dùng với type thật sự sau khi đã run code.
- compile time là apply trước, kiểu như hard-code zậy.
Đây gần như là cái cực kì phổ biến. Một instance của lớp nào đó hành động thay (làm gìum) cho một instance khác.
protocol DisplayNameDelegate { func displayName(name: String) } struct Person { var displayNameDelegate: DisplayNameDelegate? var firstName = "" { didSet { displayNameDelegate?.displayName(name: getFullName()) } } var lastName = "" { didSet { displayNameDelegate?.displayName(name: getFullName()) } } init() {} func getFullName() -> String { return "\(firstName) \(lastName)" } } struct MyDisplayNameDelegate: DisplayNameDelegate { func displayName(name: String) { print("Name: \(name)") } } var displayDelegate = MyDisplayNameDelegate() var person = Person() person.displayNameDelegate = displayDelegate person.firstName = "a" person.lastName = "Hoffman"
didSet được xem như là một property observers.