Swift中的协议

2017-10-12  本文已影响10人  keisme

1. 协议语法

protocol SomeProtocol {
    // code
}

要让自定义类型遵循某个协议,在类型名称后加上协议名称即可,中间以冒号(:)分隔,遵循多个协议时,各协议之间用逗号()分隔:

struct SomeStruct: FirstProtocol, AnotherProtocol {
    // code
}

拥有父类的类在遵循协议时,应该将父类名放在协议名之前,以逗号分隔:

class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {
    // code
}

2. 属性要求

protocol SomeProtocol {
    var mustBeSettable: Int { get set } //可读可写的变量属性
    var doesNotNeedToBeSettable: Int { get } //可读变量属性
}
protocol AnotherProtocol {
    static var someTypeProperty: Int { get set } //类型属性,还可以用class关键字声明
}

如下所示,这是一个只含有一个实例属性要求的协议。这个协议表示,任何遵循FullyNamed的类型,都必须有一个可读的String类型的实力属性fullName

protocol FullyNamed {
    var fullName: String { get }
}

下面是一个遵循FullyNamed协议的简单结构体:

struct Person: FullyNamed {
    var fullName: String
}

let john = Person(fullName: "John Higgins")

下面是一个更为复杂的类,它适配并遵循了FullyNamed协议:

class StarShip: FullyNamed {
    var prefix: String?
    var name: String
    init(name: String, prefix: String? = nil) {
        self.name = name
        self.prefix = prefix
    }
    var fullName: String {
        return (prefix != nil ? prefix! + " " : "") + name
    }
}

var ncc1701 = StarShip(name: "Enterprise", prefix: "USS")
print(ncc1701.fullName)
// print "USS Enterprise"

3. 方法要求

protocol SomeProtocol {
    static func someTypeMethod() // 类方法还可以用class关键字修饰
}

下面的例子定义了一个只含有一个实例方法的协议:

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
    }
}

4. Mutating方法要求

实现协议中的mutating方法时,若是类类型,则不用写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() // On

5. 构造器要求

protocol SomeProtocol {
    init(someParameter: Int)
}

class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // 构造器实现部分
    }
}

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

class SomeSuperClass {
    init() {
        // 构造器实现部分
    }
}

class SomeSubClass: SomeSuperClass, SomeProtocol {
    required override init() {
        // 构造器实现部分
    }
}

6. 协议作为类型

class Dice {
    let sides: Int
    let generator: RandomNumberGenerator
    init(sides: Int, generotor: RandomNumberGenerator) {
        self.sides = sides
        self.generator = generator
    }
    func roll() -> Int {
        return Int(generator.random() * Double(sides)) + 1
    }
}

generator属性的类型为RandomNumberGenerator,因此任何遵循了RandomNumberGenerator协议的类型的实例都可以赋值给generator,除此之外并无其他要求。

7. 委托(代理)模式

protocol SayHelloDelegate {
    func sayHello(name: String)
}

class ClassA {
    var delegate: SayHelloDelegate?
    var name = "Lucy"
    func play() {
        delegate?.sayHello(name: name)
    }
}

class ClassB: SayHelloDelegate {
    var name = "Lily"
    func sayHello(name: String) {
        print("\(name) 请 \(self.name) 帮她 say Hello")
    }
}

var ca = ClassA()
var cb = ClassB()
ca.delegate = cb
ca.play()
// print "Lucy 请 Lily 帮她 say Hello"

8. 协议中添加扩展

protocol Score {
    var math: Int { get set }
    var english: Int { get set }
    func mathPercent() -> Double
}

struct Puple: Score {
    var math: Int
    var english: Int
    func mathPercent() -> Double {
        return Double(math) / Double(math + english)
    }
}

let p1 = Puple(math: 90, english: 80)
p1.mathPercent() // 0.529

extension Score {
    func mathPercent() -> Double {
        return Double(math) / Double(math + english)
    }
}

struct CollageStudent: Score {
    var math: Int
    var english: Int
}

let c1 = CollageStudent(math: 80, english: 80)
c1.mathPercent() // 0.5

如此,我们可以不实现mathPercent方法也能计算出数学所占分数的比例。

上一篇下一篇

猜你喜欢

热点阅读