Swift protocol 系列之 基础介绍

940 阅读3分钟

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」。

协议是swift中一个非常强大的特性。可以说是与 泛型、函数并称为swift 的三大基石也不为过。

协议

协议是描述一些属性和方法的接口,用于指定特定的类型属性或实例属性。属性要求由“var”关键字声明为属性变量。

protocol NameProtocol {
   var name: String { get set }
   var successed: Bool { get }
   func getName() -> String
}

协议初始化

Swiftng 允许用户以遵循类似于普通类型初始化的方式来初始化协议。如果类来继承协议必须实现协议的初始化方法,并且必须写上的required关键字。

protocol NameProtocol {
   init(name: String)
}

class Person: NameProtocol {
   required init(name: String) {
   }
}

协议一致性在所有子类上通过“required”修饰符确保显式或继承实现。当子类覆盖其超类初始化要求时,它由“override”关键字指定。

protocol NameProtocol {
   init(name: String)
}

class MainClass {
   var name: String       
   init(name: String) {
      self.name = name  
   }
}

class SubClass: mainClass, NameProtocol {
   var context: String
   init(name: String, context : String) {
      self.context = context
      super.init(name:name)
   }

   required override convenience init(name: String) {
      self.init(name:name, context:"")
   }
}

协议组合

Swift 的Hashable协议继承Equatable,而Comparable也继承自Equatable,这个就有点像我们一个个相同的功能点写成一个个协议。 Swift 还允许我们使用类型别名将两个协议组合在一起,这样就会使协议易于组合而功能明确。就像SwiftCodable协议正是已这样的方式去实现的。

typealias Codable = Decodable & Encodable

协议扩展

单写协议方法申明而不去实现,这样也符合协议的要求,但是为这些协议方法提供默认实现是有用的,而且在实际过程中也是很常见的。因为提供协议方法的默认实现和协议属性的默认值,从而使它们“可选”的。这样符合协议的类型可以自己的重新实现或使用默认的实现。而且如果多个类型的实现逻辑是一样的那么使用默认实现可能提炼,而无需单独给每个类型去重复一遍去实现。使用默认行为扩展现有协议的能力非常强大,允许协议增长和扩展,而不必担心破坏现有代码的兼容性。

protocol NameProtocol {
   func getName() -> String
}

extension NameProtocol {
    func getName() {
        return "name"
    }
}

同时 Swift 允许我们使用where关键字将此类条件添加到协议扩展中。这样做可以做到仅为适用于某些情况去实现。

extension NameProtocol where Self: UIViewController {
    func getName() {
        return "UIViewController"
    }
}

上面代码片段中的Self(大写“S”)指的是类型(结构、类或枚举)。通过指定职业就可以只为继承自 UIViewController的类型扩展协议。

仅限类的协议

有时候你希望能够限制您的协议在类里,以便只有类才能符合它是很有用的。当您想要调用协议方法时:类可以自由地改变它们的变量属性,而结构则不能。在Swift 代码中声明仅类协议的正确方法是使用AnyObject

protocol MyProtocol: AnyObject { }

但是你看别人的以前旧的代码的时候你发现这样的仅限类的协议(这是旧的实现):

protocol MyProtocol: class { }

协议冲突

protocol P1 {
    var name: String { get set }
    func method()
    //some other methods
}

protocol P2 {
    var name: String { get set }
    func method()
    //some other methods
}

extension P1 {
    func method() {
        print("Method P1")
    }
}

extension P2 {
    func method() {
        print("Method P2")
    }
}

当有一个有一个类型,它符合这两种协议。在这种情况下,我们遇到了不明确的方法或者属性的实现问题。该类型并没有清楚地表明它应该使用哪个协议的方法去实现。这里提供俩个思路:

  • 1、在继承里面自己实现不明确的方法或者属性。
struct Name: P1, P2 {
    var name: String
    func method() {
        print("Method S")
    }
}
  • 2:将协议作为类型的来操作。
struct Name {
    var p1: P1
    var p2: P2
    func method() {
       _ = p1.name
       _ = p2.name
        p1.method()
        p2.method()
    }
}