Swift协议基础

协议规定了实现某些功能的方法、属性。类、结构体或枚举都可以遵循协议,并提供协议的具体实现。

语法

定义方式:

1
2
3
protocal SomeProtocol{
//协议的属性、方法等
}

自定义类型遵循某个协议:

1
2
3
struct SomeStructure: FirstProtocol, AnotherProtocol{
//结构体定义部分
}

拥有父类的类在遵循协议:

1
2
3
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
// 类的定义部分
}

属性要求

  • 协议可以要求遵循协议的类型提供特定名称和类型的实例属性或类型属性。

  • 协议不指定属性是存储型属性还是计算型属性,只指定属性的名称和类型以及属性的可读性可写性。

  • 协议指定的属性可读可写,则属性不能是常量属性或只读的计算型属性。

  • 如果协议只要求属性可读,则该属性可以是可读的,也可以是可读可写的。

  • 协议总是用var来声明变量属性,在类型声明后加{set get}{get}来表示属性可读可写或可读:

    1
    2
    3
    4
    protocol SomeProtocol {
    var mustBeSettable: Int { get set }
    var doesNotNeedToBeSettable: Int { get }
    }
  • 类型属性总是用static前缀,如果是类还可以用class

    1
    2
    3
    protocol AnotherProtocol{
    static var someTypeProperty: Int{ get set }
    }

方法要求

  • 遵循协议的类型需要实现协议里指定的实例方法或类方法。

  • 协议中的方法可以有可变参数,但参数不能有默认值。

    1
    2
    3
    4
    protocol SomeProtocol{
    static func someTypeMethod()
    func random() -> Double
    }

mutating方法要求

在值类型实例方法中要修改该类型的属性,需要在该方法前加mutating前缀。

在协议中定义的实例方法,如果方法会改变遵循该协议的类型的实例,需要在方法前mutating关键字。

实现协议中的 mutating 方法时,若是类类型,则不用写 mutating 关键字。而对于结构体和枚举,则必须写 mutating 关键字。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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()

构造器要求

协议可以要求遵循协议的类型实现指定的构造器。协议里指定构造器:

1
2
3
protocol SomeProtocol{
init(someParameter: Int)
}

在遵循协议的类中实现构造器,必须在构造器前加required修饰符:

1
2
3
4
5
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// 构造器的实现部分
}
}

使用 required 修饰符可以确保所有子类也必须提供此构造器实现,从而也能符合协议。如果类已经被标记为 final,那么不需要在协议构造器的实现中使用 required 修饰符,因为 final 类不能有子类。

如果一个子类重写了父类的指定构造器,并且该构造器满足了某个协议的要求,那么该构造器的实现需要同时标注 requiredoverride 修饰符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protocol SomeProtocol {
init()
}

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

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

可失败的构造器:

遵循协议的类型可以通过可失败构造器(init?)或非可失败构造器(init)来满足协议中定义的可失败构造器要求。协议中定义的非可失败构造器要求可以通过非可失败构造器(init)或隐式解包可失败构造器(init!)来满足。