Protocol in Swift

- 8 mins

Khái niệm:

trong Tiếng việc có nghĩa là giao thức, định chuẩn

A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.

A blueprint is a reproduction of a technical drawing, documenting an architecture or an engineering design, using a contact print process on light-sensitive sheets.

Nói một cách ngắn ngọn, protocol là giống như việc bạn định nghĩa trước hành vi, cấu trúc của một viewcontroller trong swift, rộng hơn là kiến trúc của toàn ứng dụng.

VD: Ta có hai màn hình A và B, từ màn hình A sang màn hình B,

Cú pháp - Syntax:

    protocol MyProtocol {
        // protocol definition goes here
    }

It is the same as declarations of class, structure and enumeration

A protocol could have a super protocol, it means its inheribility

    protocol MyProtocol, FirstProtocol, SecondProtocol {
        // protocol definition goes here
    }

Rằng buộc về thuộc tính - Property Requirements .

Một protocol có thể yêu cầu đối tượng thể hiện bởi Protocol đó cung cấp một thuộc tính chỉ với một tên biến và loại dữ liệu của biến đó.

Không phân biệt nó là thuộc tính lưu trữ(stored property) hay thuộc tính được tính toán(Computed property).

Ta có ví dụ cho hai trường hợp trên như sau:

protocol FullNamed {
    var firstName:String { set get }
    var lastName:String { set get }
    
    var fullName:String { get }
}


struct Person:FullNamed {
    var firstName: String
    var lastName: String
    
    var fullName: String {
        return "\(lastName) \(firstName)"
    }
}

let person = Person(firstName: "Benjamin", lastName: "Bui")

Ta khai báo một lớp Person mà có rằng buộc biến được khai báo từ protocol FullNamed. Với firstName và lastName là hai thuộc tính có thể gán lại được giá trị và lấy được giá trị.

Note:

error: variable with a setter must also have a getter

Rằng buộc về phương thức trên trong protocol - Method requirements

The following example will extend the above protocol with specific instance methods.

protocol FullNamed {
    var firstName:String { set get }
    var lastName:String { set get }
    
    func getFullName() -> String
}

struct Person:FullNamed {
    var firstName: String
    var lastName: String
    
    init(firstName:String,lastName:String) {
        self.firstName = firstName
        self.lastName = lastName
    }
    
    func getFullName() -> String {
        return "\(lastName) \(firstName)"
    }
}
let person = Person(firstName: "Benjamin", lastName: "Bui")
print(person.getFullName())

/* output 
 Bui Benjamin
 
 */

Rằng buộc khởi tạo - Initializer Requirements

Rằng buộc phương thức thay đổi - Mutating Method Requirements

It mean you will declare a function in struct or enumeration where you can change value of property in, because you can not change value of property in normal function.

With protocol, to do this you have to add prefix mutating

protocol FullNamed {
    var firstName:String { set get }
    var lastName:String { set get }
    
    mutating func setName(withAnotherFullname fullname:FullNamed)
}

struct Person:FullNamed {
    ...
    mutating func setName(withAnotherFullname fullname: FullNamed) {
        firstName = fullname.firstName
        lastName = fullname.lastName
    }
}

Protocol là một loại dữ liệu - Protocols as Types

Because it is a type, you can use a protocol in many places where other types are allowed, including:

Sự ủy quyền - Delegation:

It is a design pattern that enables a class or structure to delegate some of its responsibilities to an instance of another type.

We are a example about modeling a people in love

protocol InLovePeople {
    var lover:String { get set }
    
    func startTheRelationship()
}

protocol InLovePeopleDelegate {
    func peopleDidGoOutTogether(people:InLovePeople)
    func peopleDidStopRelationship(people:InLovePeople)
    func peopleWillMakeWedding(people:InLovePeople)
}


class InLoveMan:InLovePeople {
    var lover: String
    
    var delegate:InLovePeopleDelegate?
    
    init(loverName:String) {
        lover = loverName
    }
    
    func startTheRelationship() {
        if lover == "Not Good" {
            delegate?.peopleDidStopRelationship(people: self)
        }
    }
}

class PeopleTracker:InLovePeopleDelegate {
    
    func peopleWillMakeWedding(people: InLovePeople) {
        print("We will be so happy!")
    }
    
    func peopleDidGoOutTogether(people: InLovePeople) {
        print("It's a good sign!")
    }
    
    func peopleDidStopRelationship(people: InLovePeople) {
        print("Poor you!")
    }
}


let man = InLoveMan(loverName: "Su Su")
let tracker = PeopleTracker()
man.delegate = tracker
man.startTheRelationship()

Note: Because a delegate isn’t required in order to do action like as its instance, the delegate property is defined as an optional

Thêm tương thích giao thức với một mở rộng - Adding Protocol Conformance with an Extension.

protocol InLovePeople {
    var lover:String { get set }
    
    func startTheRelationship()
}

extension InLoveMan: InLovePeople {
    var faceExpression: String {
        return "It look like confident and enjoyable with life"
    }
}

Việc khai báo làm theo với một sự mở rộng - Declaring Protocol Adoption with an Extension.

class InLoveMan {
    var lover: String
    
    var delegate:InLovePeopleDelegate?
    
    init(loverName:String) {
        lover = loverName
    }
    
    func startTheRelationship() {
        if lover == "Not Good" {
            delegate?.peopleDidStopRelationship(people: self)
        }
    }
}

class InLoveMan:InLovePeople { }

Note:

Types do not automatically adopt a protocol. They must always explicitly declare their adoption of the protocol.

Việc kế thừa của giao thức - Protocol Inheritance:

A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits.

Các giao thức chỉ giành cho lớp - Class-Only Protocols:

You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObject protocol to a protocol’s inheritance list.

protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
    // class-only protocol definition goes here
}

Sự kết hợp giữa các giao thức - Protocol Composition

It mean you can define a temporary local protocol that has the combined requirements of all protocols in the composition.

It has the form SomeProtocol & AnotherProtocol

protocol InLovePeople {
    var lover:String { get set }
    
    func startTheRelationship()
}

protocol InPassionPeople {
    var profession:String { get set }
    
    func startThePassion()
}

struct HappyPerson: InLovePeople, InPassionPeople  {
    var lover:String
    var profession:String

    ...
}

func wantToBeHappyPerson(likeThis person:InLovePeople & InPassionPeople) {
    print("Yes, I want to be like \(person.lover) \(person.profession)")
}

Kiểm tra biến loại protocol - Checking for Protocol Conformance

You can use the is and as operators to check for Protocol conformance, and to cast to a special protocol.

let object = HappyPerson(lover:"Her",profession:"Designer")

if let workLover = object as? InPassionPeople {
    print("He is awesome!")
}

Rằng buộc tùy chọn cho giao thức - Optional Protocol Requirements:

Optional requirements for protocol do not have to do implemented by types that conform to the protocol. Opitional requirements are prefixed by the optional modifier as part of the protocol’s definition and you can write code that interoperates with Objective-C. Both the protocol and the optional requirement must be marked with the @obj attribute.

Note: @obj protocols can be adopted only by classes that inherit from Objective-C classes or other @obj classes

@objc protocol HappyPersonDataSource {
    @objc optional func goAhead()
    @objc optional var objective: String { get }
}

## 

Protocol Extensions

Protocols can be extended to provide method and property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function.

extension InLovePeople {
    func isThinkingAboutThatPerson() -> bool
}

Default Implementations

You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol.

Adding Constraints to Protocol Extensions

When you define a protocol extension, you can specify constraints that conforming types must satisfy before the methods and properties of the extension are available. You write these constraints after the name of the protocol you’re extending using a generic where clause.

extension Collection where Iterator.Element: InLovePeople {
    func sayLoveTogether() -> String {
        return "Love All of you"
    }
}

let lovers = [InLoveMan(loverName:"Zun"),InLoveMan(loverName:"Zun")]
lovers.sayLoveTogether()

Reference:

  1. Protocols - Apple
comments powered by Disqus
rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora