At WWDC15, Apple announced Swift as the world’s first protocol oriented programming (POP) language. POP is more flexible than traditional object-oriented programming (OOP). RxSwift and ReactorKit cores are also protocol oriented programming.

What is POP

To figure out what protocol Oriented (POP) is, what is the Swift protocol? We define a simple Swift protocol as follows:

protocol Runable {
    var name: String { get }
    func run()
}
Copy the code

The code defines a protocol called Runable that contains a name attribute and a definition of a run method. A protocol is a set of attributes and/or method definitions, and if a specific type wants to comply with a protocol, it needs to implement all of those things defined by that protocol. All a protocol really does is “a contract about implementation.”

Protocol oriented programming (POP) is a new programming paradigm introduced by Swift2.0. POP is designed to write code through protocol extension, protocol inheritance, and protocol composition.

Why use Protocol Oriented Programming (POP)

Swift is an object-oriented language with classes that meet all of our needs and powerful capabilities. Why POP?

First, in Swift, value types take precedence over classes. However, object-oriented concepts do not work well with structures and enumerations: structures and enumerations cannot be inherited. Therefore, inheritance, a feature of object orientation, cannot be applied to value types.

Again, in real development projects, we often encounter the following scenario: Suppose we have a ViewController that inherits from UIViewController, and we add a new method to it, customMethod:

Class ViewController: UIViewController {// Add funccustomMethod() {}}Copy the code

At this point we have another OtherViewController that inherits from UITableViewController, and we also need to add a method customMethod to it

Class OtherViewController: UITableViewController {// Add funccustomMethod() {}}Copy the code

Here’s the problem: it’s hard to share code between classes with different inheritance relationships. Our focus, customMethod, is on two inheritance chains UIViewController -> ViewCotroller and UIViewController -> UITableViewController -> AnotherViewController on the cross section. Object orientation is a good way to abstract, but certainly not the best way. It doesn’t describe the fact that two different things have the same property. Here, the combination of features is closer to the nature of things than inheritance.

In this case, we have the following solutions:

  • Copy & Paste This is a bad solution and should be avoided as much as possible.

  • BaseViewController adds shared code to a BaseViewController that inherits from UIViewController, or adds extension to UIViewController. This is a common solution for many people these days, but if you do it over and over again, the so-called BaseViewController can quickly become a garbage dump. Responsibilities aren’t clear, anything can be thrown into Base, you have no idea what classes are out of Base, and the impact of this “superclass” on your code is unpredictable.

  • Dependency injection provides this functionality with a new type by passing in an object with a customMethod. This is a slightly better approach, but introducing additional dependencies may be something we don’t want.

  • Multiple inheritance Of course, Swift does not support multiple inheritance. With multiple inheritance, though, we could inherit from multiple parent classes and add customMethod in place, but that would cause other problems.

In general, the benefits of protocol oriented programming (POP) are as follows:

  • Structs and enumerated equivalence types can also be used
  • In order to inherit multiple protocols, make up for the deficiency of single class inheritance in SWIFT
  • Enhance code extensibility and reduce code redundancy
  • Make projects more componentized and code more readable
  • Make unnecessary functional code into a functional block for easier unit testing.

Use POP to solve the above problems

Define a protocol with customMethod ex:

protocol ex {
    func customMethod();
}
Copy the code

Abide by this protocol in actual types:

extension ViewController :ex {
    func customMethod() {
        //
    }
}
extension OtherViewController : ex {
    func customMethod() {//}}Copy the code

Just like Copy & Paste, you have to write it in both ViewController and OtherViewController. Is there any way to solve this problem? That’s protocol extension

You can add an implementation for customMethod in Extension Ex:

extension ex {
    func customMethod() {//}}Copy the code

With this protocol extension, you can use customMethod directly by declaring that ViewController and OtherViewController follow EX.

4. Characteristics and use of the protocol

Protocol extension:

  • 1. Provide default implementations of protocol methods and default values for protocol properties, making them optional; Protocol-compliant types can provide their own implementation or use the default implementation.
  • 2. Add additional method implementations that are not declared in the protocol and can be used by any type of implementation protocol. This allows you to add specific methods to protocol-compliant types
protocol Entity {
    var name: String {get set}
    static func uid() -> String
}

extension Entity {
    static func uid() -> String {
        return UUID().uuidString
    }
}

struct Order: Entity {
    var name: String
    let uid: String = Order.uid()
}
let order = Order(name: "My Order")
print(order.uid)
Copy the code

Agreement inheritance

Protocols can inherit from other protocols and then add functionality on top of the requirements it inherits, thus providing a more granular and flexible design.

protocol Persistable: Entity { func write(instance: Entity, to filePath: String) init? (by uid: String) } struct InMemoryEntity: Entity { var name: String } struct PersistableEntity: Persistable { var name: String func write(instance: Entity, to filePath: String) { // ... } init? (by uid: String) { // try to load from the filesystem based on id } }Copy the code

Combination of protocols

Classes, structures, and enumerations can conform to multiple protocols, and they can take default implementations of multiple protocols. This is similar in concept to multiple inheritance. This combination is not only more flexible than squeezing all the required functionality into a single base class, but also applies to value types.

struct MyEntity: Entity, Equatable, CustomStringConvertible {
    var name: String
    // Equatable
    public static func ==(lhs: MyEntity, rhs: MyEntity) -> Bool {
        return lhs.name == rhs.name
    }
    // CustomStringConvertible
    public var description: String {
        return "MyEntity: \(name)"}}let entity1 = MyEntity(name: "42")
print(entity1)
let entity2 = MyEntity(name: "42")
assert(entity1 == entity2, "Entities shall be equal")
Copy the code