OOP and POP

The essence of Object Oriented Programming is the abstract thinking process and Object Oriented method reflected by establishing model. Models are meant to characterize things in the real world. Any model can not reflect all the specific characteristics of objective things, but can only be an abstraction of the characteristics and change rules of things, and describe the characteristics of the object more generally, more centrally and more profoundly within the scope it involves. The abstraction achieved through the establishment of models is the deepening of people’s understanding of objects

It is because of the efficacy of the whole, convenient storage and transmission of data! Object-oriented design, adopted in many languages! Oc-swift is also OOP. This is already very familiar to everyone, and it is no longer verbose here. Today’s main character is Protocol Oriented Programming (POP) a Protocol Oriented Programming

Object oriented dilemma

Wang Wei for protocol programming this article there is a detailed expression!

  • Crosscutting concern
  • Dynamic distribution security
  • Diamond defects

POP protocol oriented programming

Protocol-oriented programming thinking is very, very important in Swift development! It can be said that if you use POP well, then your project is definitely not a level

POP addresses crosscutting concerns

Cross-cutting Concerns are that it’s hard to share code in classes with different inheritance relationships! Now that we’re protocol oriented, anyone that follows the protocol can add the name attribute and the sayHello() method by default!

Protocol LGProtocl {var name: String {get} func sayHello()}Copy the code
  • But there’s a problem: lack of implementation! If I did that, I would have to implement it in every single class, and a lot of times these methods are actually common and don’t need a lot of implementation specificity
  • Fortunately, inWWDC 2015 ε’Œ Swift 2When released,AppleA new feature has been introduced for the protocolProtocol extensionsIt brought about a revolutionary change in the Swift language.
struct LGTeacher: LGProtocl{
    var name: String
    func sayHello() {
        print("Hello")}}Copy the code
  • The protocol definition provides an entry point for implementation, which must be implemented according to the protocol type
  • Protocol extension to provide a default implementation of the entry. Additional implementations are provided depending on the entry

What does this operation do? Everything is LG

Extension LGCompatible {Reactive extensions. Public static var Reactive extensions: LGRxSwift.Reactive<Self>.Type /// Reactive extensions. public var lg: LGRxSwift.Reactive<Self>} NSObject: LGCompatible {}Copy the code
  • This perfectly realizes lg’s feature that everything is lg
  • Then throughLGCompatibleOnly theReactiveA responsive class or structure
  • And finally by expandingReactiveThe ability to fit in perfectly

POP addresses dynamic distribution security

For types that do not implement LGProtocl, the compiler returns an error, so there is no case of messages being sent by mistake

// Compiler Error: 
// 'LGTeacher' does not conform to protocol 'LGProtocl'
// protocol requires function 'sayHello()'
Copy the code

POP addresses the diamond defect

Finally, let’s look at multiple inheritance. An important problem with multiple inheritance is the diamond defect, in which subclasses cannot determine which parent class’s methods to use. In terms of protocol correspondence, this problem remains, but it can only be safely determined.

Unfortunately, POP has the same BUG in solving the rhombus BUG, because multiple protocols have the same protocol attributes, protocol methods, and adherence is not determined! ⚠️ we in the usual development must try to avoid the same protocol to follow the problem, we must do in the module division above thoroughly, although Swift can not deal with the conflict of multiple protocols well, but we can in the protocol layer function extraction layer strictly intelligent processing up and down function.

For example: 🌰

  • Did we just make LGCompatible, which is the gateway to our functionality, where everything comes in lg, so this layer protocol just needs to provide the gateway

  • At the same time, it provides interface transition capability to transition LG of LGReactiveCompatible to Reactive

extension LGReactiveCompatible {
    /// Reactive extensions.
    public static var lg: Reactive<Self>.Type {
        get { return Reactive<Self>.self }
        set {// this enables using Reactive to "mutate" base type }
    }
    /// Reactive extensions.
    public var lg: Reactive<Self> {
        get { return Reactive(self) }
        set { // this enables using Reactive to "mutate" base object }
    }
}
Copy the code
  • ReactiveLayer, according to the business division, to achieve the effect of logic code sinking!
public struct Reactive<Base> {
    public let base: Base
    public init(_ base: Base) {
        self.base = base
    }
}
Copy the code
  • According to theReactiveInwardly relatedBaseType to identify different responsive functions
  • Such as:extension Reactive where Base: UISwitchAmong themUISwitchCan be replaced byUITableView, UITextField, UIView. Continuous business sinking!

I’m sure you’ve seen the benefits of protocol-oriented programming here, but there’s one very important feature that doesn’t show up: much less coupling, more layered code, and clearer logic

POP network

In our actual development, network request is a very important module

Alamofire.request("http://127.0.0.1:5000/pythonJson/") .validate(statusCode: 200.. <300) .validate(contentType: ["application/json"])
    .responseData { response in
        switch response.result {
        case .success:
            print(response)
            let _ = LGLoginClient.lgJson(data: response.data)
        case .failure(let error):
            print(error)
        }
}
Copy the code
  • The above code, there is no mistake! But if you are an experienced iOS developer, you will find problems!
  • If you were directly inViewController(on behalf of the application layer) directly such a network request, the degree of coupling is very large (application layer and network layer coupled together)
  • There are nesting everywhere, reusability is particularly low
  • The application layer shouldn’t care about network requests at allMethod, interface, and parameterFrankly, I don’t want to care
  • If the system is modular, then I am very happy πŸ˜„πŸ˜„πŸ˜„

1️ retail: Network information capacity

enum LGHTTPMethod: String {
    case GET
    case POST
}

protocol LGRequest {
    var host: String { get }
    var path: String { get }
    var method: LGHTTPMethod { get }
    var parameter: [String: Any] { get }
    
    associatedtype Response
    func parse(data: Data) -> Response?
}
Copy the code
  • LGHTTPMethodProvide this moduleLGRequestEnumeration of required request methods
  • LGRequestIs the request enabler of the login registration module, which provides capabilities to our module in a protocol-oriented manner
  • ResponseThis association type is convenient for laterjsonGo to the model and set the generic type to be generic

2️ retail: Module information layer

struct LGLoginRequest: LGRequest {
    typealias Response = LGPerson
    let name: String
    
    let host = "http://127.0.0.1:5000"
    var path: String {
        return "/pythonJson/getTeacherInfo/? username=\(name)"
    }
    let method: LGHTTPMethod = .GET
    let parameter: [String: Any] = [:]
    
    func parse(data: Data) -> LGPerson? {
        return LGPerson(data: data)
    }
}
Copy the code
  • LGLoginRequestfollowLGRequestTo obtainHost, path, method, parameter, parseProcessing power, here can be directly processed, there is no need to go to the application layer to pass the value!

3️ discount: network request capacity

extension LGRequest {
    func send(handler: @escaping (Response?) -> Void) {
        let url = URL(string: host.appending(path))!
        var request = URLRequest(url: url)
        request.httpMethod = method.rawValue
        let task = URLSession.shared.dataTask(with: request) {
            data, response, error in
            if let data = data, let res = self.parse(data: data) {
                DispatchQueue.main.async { handler(res) }
            } else {
                DispatchQueue.main.async { handler(nil) }
            }
        }
        task.resume()
    }
}
Copy the code
  • Because of protocol orientation, we use protocols to provide common network request capabilities
  • Among themResponseIs the specific type of the corresponding model

4️ retail: application layer call

override func viewDidLoad() {
    super.viewDidLoad()
    let request = LGPersonRequest(name: "Cooci")
    request.send { (person) inself.updataUI(person: person!) }}Copy the code
  • The application layer is completely separated from the network layer
  • The application layer only provides necessary parameter information. Which interface to call and how to handle it
  • LGPersonRequestModule information processing provides layer
  • LGPersonRequestIt also has the ability to call the network

5️ retail: Optimization and reconstruction of POP network

Apparently our LGRequest guy is too capable! Can provide information, can also initiate requests, even serialization processing power is provided by LGRequest! Optimization and reconstruction is imminent…

1: Information provider

protocol LGRequest {
    var path: String { get }
    var method: LGHTTPMethod { get }
    var parameter: [String: Any] { get }
    
    associatedtype Response: LGDecodable
}

struct LGPersonRequest: LGRequest {
    typealias Response = LGPerson
    
    let name: String
    var path: String {
        return "/pythonJson/getTeacherInfo/? username=\(name)"
    }
    let method: LGHTTPMethod = .GET
    let parameter: [String: Any] = [:]
}
Copy the code
  • Put publicly providedhostTaken out
  • No longer provideLGRequestNetwork request capability
  • Serialization is delivered to the concrete model, providing a serialization capabilityLGDecodable
protocol ClientProtocol {
    var host: String { get }
    func send<T: LGRequest>(_ r: T, handler: @escaping (T.Response?) -> Void)
}


class LGClient: ClientProtocol{
    static let manager = LGClient()
    let host: String = "http://127.0.0.1:5000"
    
    func send<T>(_ r: T, handler: @escaping (T.Response?) -> Void) where T : LGRequest {
        
        let url = URL(string: host.appending(r.path))!
        var request = URLRequest(url: url)
        request.httpMethod = r.method.rawValue
        let task = URLSession.shared.dataTask(with: request) {
            data, response, error in
            if let data = data, let res = T.Response.parse(data: data) {
                DispatchQueue.main.async { handler(res) }
            } else {
                DispatchQueue.main.async { handler(nil) }
            }
        }
        task.resume()
    }
}
Copy the code
  • Provides a network management classLGClient
  • Manage network request capabilities and common provisioning parameters

2: network capability provider

class LGLoginClient: LGClient {
    
    override func send<T>(_ r: T, handler: @escaping (T.Response?) -> Void) where T : LGRequest {
        
        switch r.path {
        case let string where string.contains("/pythonJson/getTeacherInfo") :print("123456")
            handler(nil)
        default:
            let url = URL(string: host.appending(r.path))!
            var request = URLRequest(url: url)
            request.httpMethod = r.method.rawValue
            let task = URLSession.shared.dataTask(with: request) {
                data, response, error in
                if let data = data, let res = T.Response.parse(data: data) {
                    DispatchQueue.main.async { handler(res) }
                } else {
                    DispatchQueue.main.async { handler(nil) }
                }
            }
            task.resume()
        }

    }
}
Copy the code
  • Module network capability layerLGLoginClientRewrite, according to the different interface block processing
  • The serialization layer is handed over to the generic model (T.Response) processing
  • Of course, you can also continue to sink the network capacity, to the specific network comprehensive requestor to deal with

3: Serialization capability provision layer

extension LGPerson: LGDecodable {
    static func parse(data: Data) -> LGPerson? {
        return LGPerson(data: data)
    }
}
Copy the code
  • Serialization is simply expressed here, and you can call some optimized tripartite framework

6 ️ ⃣ : summary

  • POP network, so that the application layer and network layer completely separated!
  • Protocol oriented programming to provide the ability to greatly expand the reuse, while the coupling degree can also be handled!
  • At the same time, this model (application layer -> information supply layer -> network layer) programming thinking is easier to understand, operation is easier to get started!
  • In addition, such programming habits are also in line with the development process (generally, it is the background developers who make corresponding interfaces before we do network debugging).
  • Later maintenance is simple, later changes, we only need to provide information layer to deal with the response configuration, there is no need to move the application layer or network layer
  • Of course, this is also the mainstream development thinking, as a mid-to-senior iOS developer does not movePOPNetwork programming then I guess you need to study hard! πŸ’ͺ πŸ’ͺ πŸ’ͺ

Recently I got some PDF documents of summary of iOS interview questions from my friends! Because the platform can not send files, friends in need can add QQ group: 679884541, there are iOS developers in the group, any problems and complaints we can communicate together!