What is protocol Oriented programming?

Protocol oriented = protocol + extension + inheritance Functions are divided by protocol and extension to reduce the coupling between modules and enhance the extensibility of code. One of the weaknesses of iOS is multiple inheritance, and protocols address multiple inheritance. In Swift, structures become more powerful, defining not only attributes but also methods, and multiple inheritance protocols, which OC does not provide.

Here’s a real column to get a feel for the power of protocol orientation.

Network request encapsulation

1. Protocol declaration -base

protocol HBRequest {
    var host: String {get}
    var path: String {get}
    var method: HBHTTPMethod {get}
    var parameter: [String : Any] {get}
    
    associatedtype Response
    func parse(data:Data) -> Response?
}
Copy the code

Declare a protocol, define the attributes associated with the request, and define the method of modeling. Note that the model does not know what type of model to convert to, so declare an associated attribute, which is externally generic model. The model here is determined by the external request configuration.

The protocol attribute should be assigned to the specific business, and the request method is used by every business module, so the request method should be treated as a public method.

2. Implement the request method

extension HBRequest {
    func send(handler: @escaping(Response?) -> Void) {
        // Request network - serialization - model
        let url = URL(string: host.appending(path))!
        var request = URLRequest(url: url)
        request.httpMethod = method.rawValue
        let task = URLSession.shared.dataTask(with: request){
            (data,reponse,error) in
            if let data = data, let resp = self.parse(data: data){
                DispatchQueue.main.async {
                    handler(resp)
                }
            }else{
                DispatchQueue.main.async {
                    handler(nil)
                }
            }
        }
        task.resume()
    }
}
Copy the code

The extended protocol implements the protocol method by placing the network request module in the method and exposing the closure externally to facilitate the internal transfer of values to the external. Data is passed out through the main thread.

Parse calls the model self.parse method to return the model. It is not implemented here. This is different from our usual sequential processing, where the model is implemented in the request configuration, in the Model. So one of the things you might think is why don’t you just return data and process it outside? So if you think about it in a closure that’s handled externally, normally the request is made in the business layer, then the business layer or the Controller layer has to handle not only the view load but also the data, then the division of labor is messed up. It’s the opposite of the MVC, MVVM architecture we want. Therefore, it makes the most sense to return the model to the business layer, leaving the data processing to the Model layer.

The protocol declared above and the extension of the protocol can be used as the base class of the request. In the same file, the business layer invokes the method directly from the request, of course, through the successor of the protocol, namely the request configuration structure in the concrete Model file.

3. Model building and serialization -model

Structures are the best vehicle for data categorization, so Model chooses them to manage our properties. The implementation is as follows:

struct HBPerson {
    let name: String
    let headimg: String
    let description: String
    
    // Data parsing
    init? (data:Data) {
        guard let obj = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String:Any] else {
            return nil
        }
        let data = obj["data"] as! [String:String]
        self.name = data["name"]!
        self.headimg = data["headimg"]!
        self.description = data["description"]! }}Copy the code
  • Setting model Properties
  • Passed in during initializationdataDo data parsing

In addition to building the model, we need to configure the network request parameters:

struct HBUserInfoRequest : HBRequest{
    var host: String = "http://onapp.yahibo.top/public/? s=api/"
    var path: String = "test/info"
    var method: HBHTTPMethod=.GET
    var parameter: [String : Any] = [:]
    
    typealias Response = HBPerson
    
    / / the serialization
    func parse(data: Data) -> HBPerson? {
        return HBPerson(data: data)
    }
}
Copy the code
  • HBUserInfoRequestInherit from the base protocol to configure the request parameters
  • Implement the basic protocol of the serialization method, the method inHBRequestCall in extension
  • The data to be processed ismodelObject returns toHBRequestIn thesendMethod so that the details can be captured at the business layermodelThe object

The above two structures can be classified as a Model class, implemented in the same file, equivalent to a model class of OC.

4. Initiate a request -controller

let request = HBLoginRequest()
request.send {[weak self] (person) in
    print(person? .headimgas Any)
    self? .imageview.kf.setImage(with:URL.init(string: ""))
    self? .nameLabel.text = person?.nameself? .descriptionLabel.text = person?.description }Copy the code

Create the request object directly and initiate the request. Perfect, at this point, the functions of each layer have been divided, namely:

Request Base Layer (Base) + Data Layer (Model) + Business layer (Controller)

The above is an example of a simple network request encapsulation that connects the model layer to the business layer via a protocol. Of course, in the previous study of RxSwift, we can feel the charm of protocol more and remove the coupling of functional modules through protocol.