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 initialization
data
Do 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
HBUserInfoRequest
Inherit from the base protocol to configure the request parameters- Implement the basic protocol of the serialization method, the method in
HBRequest
Call in extension - The data to be processed is
model
Object returns toHBRequest
In thesend
Method so that the details can be captured at the business layermodel
The 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.