美文网首页
Swift中的协议

Swift中的协议

作者: keisme | 来源:发表于2017-10-12 16:07 被阅读10次

    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方法也能计算出数学所占分数的比例。

    相关文章

      网友评论

          本文标题:Swift中的协议

          本文链接:https://www.haomeiwen.com/subject/pokoyxtx.html