免费开源的iOS开发学习平台

Swift:18 协议

协议中可以定义一些方法、属性以供类、结构体或枚举遵循。除了遵循协议的类型必须实现的要求外,还可以对协议进行扩展,通过扩展来实现一部分要求或者实现一些附加功能,这样遵循协议的类型就能够使用这些功能。

协议语法

协议的定义方式与类、结构体和枚举的定义非常相似,使用关键字protocol来定义协议。要让自定义类型遵循某个协议,在定义类型时,需要在类型名称后加上协议名称,中间以冒号(:)分隔。遵循多个协议时,各协议之间用逗号(,)。如果该类型有父类,则父类需要写在协议的前面。

protocol FirstProtocol {
    // 这里是协议的定义部分
}

protocol SecondProtocol {
    // 这里是协议的定义部分
}

class SuperClass{
    
}

class SomeClass:SuperClass,FirstProtocol,SecondProtocol{
    
}

属性要求

协议可以要求遵循协议的类型提供特定名称和类型的实例属性或类型属性。协议不指定属性是存储型属性还是计算型属性,它只指定属性的名称和类型。此外,协议还指定属性是可读的还是可读可写的。

如果协议要求属性是可读可写的,那么该属性不能是常量属性或只读的计算型属性。如果协议只要求属性是可读的,那么该属性不仅可以是可读的,如果代码需要的话,还可以是可写的。

//指定实例属性
protocol SomeProtocol {
    var mustBeSettable: Int { get set }
    var doesNotNeedToBeSettable: Int { get }
}

//指定类型属性
protocol AnotherProtocol {
    static var someTypeProperty: Int { get set }
}

方法要求

协议可以要求遵循协议的类型实现某些指定的实例方法或类方法。这些方法作为协议的一部分,像普通方法一样放在协议的定义中,但是不需要大括号和方法体。可以在协议中定义具有可变参数的方法,和普通方法的定义方式相同。但是,不支持为协议中的方法的参数提供默认值。

//类型方法
protocol SomeProtocol {
    static func someTypeMethod()
}
//实例方法
protocol RandomNumberGenerator {
    func random() -> Double
}

Mutating方法要求

如果你在协议中定义了一个实例方法,该方法会改变遵循该协议的类型的实例,那么在定义协议时需要在方法前加mutating关键字。这使得结构体和枚举能够遵循此协议并满足此方法要求。

protocol Togglable {
    mutating func toggle()
}

enum OnOffSwitch: Togglable {
    case off, on
    mutating func toggle() {
        switch self {
        case .off:
            self = .on
        case .on:
            self = .off
        }
    }
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle()
// lightSwitch 现在的值为 .On

构造器要求在类中的实现

你可以在遵循协议的类中实现构造器,无论是作为指定构造器,还是作为便捷构造器。无论哪种情况,你都必须为构造器实现标上 required 修饰符。使用 required 修饰符可以确保所有子类也必须提供此构造器实现,从而也能符合协议。

protocol SomeProtocol {
    init()
}

class SomeSuperClass {
    init() {
        // 这里是构造器的实现部分
    }
}

class SomeSubClass: SomeSuperClass, SomeProtocol {
    // 因为遵循协议,需要加上 required
    // 因为继承自父类,需要加上 override
    required override init() {
        // 这里是构造器的实现部分
    }
}

协议扩展

协议可以通过扩展来为遵循协议的类型提供属性、方法以及下标的实现。通过这种方式,你可以基于协议本身来实现这些功能,而无需在每个遵循协议的类型中都重复同样的实现,也无需使用全局函数。

protocol RandomNumberGenerator {
    func random() -> Double
}

class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
    func random() -> Double {
        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))
        return lastRandom / m
    }
}

extension RandomNumberGenerator {
    func randomBool() -> Bool {
        return random() > 0.5
    }
}

let generator:RandomNumberGenerator = LinearCongruentialGenerator()
print("生成一个随机数: \(generator.random())")
print("再生成一个随机数: \(generator.random())")
print("生成一个随机布尔值: \(generator.randomBool())")
``
代码执行结果如下图所示。
    
<img src="http://qiniu.99ios.com/99ios/1486721587524.png" width="593"/>

# 示例代码
<https://github.com/99ios/23.19>

---