Swift_学习笔记_协议

来源:互联网 发布:网络上的唱歌比赛 编辑:程序博客网 时间:2024/06/04 17:52
  • 协议:代理设计模式
  • 协议能够被类、枚举、结构体实现,满足协议要求的类、枚举、结构体被称为协议的是实现者。

协议的语法

  • 在类、枚举、结构体的名称后加上协议名称,中间以冒号(:)分隔,即可实现协议,当实现多个协议时,多个协议间用逗号(,)隔开。
    • eg. class 类名:协议1,协议n{}
  • 如果类含有父类,则应当将父类放在所有的协议之前。
    • eg. class 类名:父类,协议1,协议n{}

属性的要求

  • 无论声明的属性为类属性还是对象属性,均需要在属性声明后加上{get}{get set},代表属性只读或读写。
  • 属性被声明为{get},为可读的属性实现{setter}方法,也不会报错。
  • 在声明类属性时,需要在声明的属性前添加关键字static
  • 在实现者内,必须实现协议的类属性的getter方法,如果协议内定义的类属性是读写的,则还必须实现setter方法。
  • 代码示例:
// 协议protocol oneProtocol{    // 定义变量,必须在属性声明后添加{get}或者{get set}    var argumentOne:Int{get} // 只读    var argumentTwo:Int{get set} // 读写    static var argumentClass:Int{get}}// 类class Person:oneProtocol{    var argumentOne: Int    var argumentTwo: Int    static var argumentClass: Int{        get{            return 30        }    }    init(argumentOne:Int,argumentTwo:Int) {        self.argumentOne = argumentOne        self.argumentTwo = argumentTwo    }}var per = Person(argumentOne: 90, argumentTwo: 1)print("\(per.argumentOne)") // 90print("\(Person.argumentClass)") // 30

方法要求

  • 协议内声明的方法不需要协议进行方法的实现。
  • 类方法,需要使用关键字static
  • 代码示例:
protocol funcProtocol{    func sayHello()    static func sayBad()}class Person:funcProtocol{    func sayHello() {        print("Hello")    }    static func sayBad() {        print("Bad")    }}

Mutating方法要求

  • 能在方法或者函数内部改变字段的方法称为Mutating方法。
  • mutating关键字表示该函数允许改变该示例和其属性的类型。
  • 一般mutating用在值拷贝的地方,例如:结构体、枚举。对于类或者类绑定协议中的方法无效。
  • 代码示例:
protocol Togglable{    mutating func toggle()}enum OnOffSwitch:Togglable{    case On,Off    mutating func toggle() {        switch self {        case .Off:            self = .On        case .On:            self = .Off        }    }}var light = OnOffSwitch.Off //Offlight.toggle()  // Onstruct OnOFF:Togglable{    var one:Int    var two:Int    mutating func toggle() {        if self.one > 10 {            self.two = 30        }else{            self.two = 20        }    }}var LIGHT = OnOFF(one: 2, two: 3)print("\(LIGHT.two)") // 3LIGHT.toggle()print("\(LIGHT.two)") // 20

使用协议规范构造函数

  • 协议可以规定必须实现指定的构造函数,比如一些类中必须要求实现init构造函数,这样就可以制造一个协议,让实现协议的类必须实现该构造函数。
  • 实现构造协议的类,必须使用关键字required
    • 代码示例:
protocol TwoProtocol{    init(twoArgument:Int)}class two:TwoProtocol{    required init(twoArgument: Int) {    }}
  • 如果父类中存在与协议内相同的构造方法,则子类在实现构造方法时,需要同时使用关键字requiredoverride
    • 代码示例:
protocol TwoProtocol{    init()}class TwoSuperClass{    init() {    }}class Two:TwoSuperClass,TwoProtocol{    required override init() {    }}
  • 不能在final类中实现构造函数协议,因为final类是不能被继承的,因此不能实现构造函数协议。
  • 如果父类内被final修饰的方法与协议内相同,则该方法不能被遵循协议的子类实现。
    • 代码示例:
protocol TwoProtocol{    func say()}class TwoSuperClass{    final func say(){        print("Super Say Hello")    }}class Two:TwoSuperClass,TwoProtocol{    // 无法实现say方法}

协议类型

  • 协议本身不实现任何功能,但是可以将它当作类型来使用。
  • 协议作为类型使用的场景:
    • 作为函数、方法或构造器中的参数类型,返回值类型。
    • 作为常量、变量、属性的类型。
    • 作为数组、字典或其它容器中的元素类型。

委托/代理设计模式

  • 委托/代理是一种设计模式,它允许类或者结构体将一些需要它们负责的功能交由给其他类型。
  • 委托模式的实现:定义协议来封装那些需要被委托的函数和方法,使实现者拥有数据源的类型。

协议的各种使用

在扩展中添加协议成员

  • 当无法修改原代码时,可以通过扩展来补充已经存在的类型。
  • 扩展可以为已经存在的类型添加属性、方法、下标、协议等成员。
  • 通过扩展为已存在的类型实现协议时,该类型的所有实例也会随之添加协议中的方法。
    代码示例:
protocol TextProtocol{    func printSomeMessage(message:String)}class Dice{}extension Dice:TextProtocol{    func printSomeMessage(message: String) {        print("\(message)")    }}let dic = Dice()dic.printSomeMessage(message: "hello");

通过扩展补充协议声明

  • 当一个类型已经实现了协议中的所有要求,却没有声明时,可以通过扩展补充协议的声明。
protocol TextProtocol{    func printSomeMessage(message:String)}struct Hamster{    func printSomeMessage(message: String) {        print("\(message)")    }}extension Hamster:TextProtocol{   // 此时,Hamster的实例也可以作为TextProtocol类型使用}let hamster = Hamster()

集合中的协议类型

  • 协议也可以作为类型在集合中被使用,表示集合中的元素均为协议类型。
let things:[TextProtocol] = [dic,hamster]for thing in things {    thing.printSomeMessage(message: "Hello Word")}// 由于thing被当作是TextProtocol类型,故都能调用printSomeMessage方法

仅在类中使用协议

  • 通过在协议中增加class关键字,可以实现协议只让类来实现。
  • 如果该协议同时继承其它协议,则需要在class后添加,并且用逗号隔开。
protocol SomeOnlyClassProtocol:class{}// 协议SomeOnlyClassProtocol实现者只能是类

协议的继承

  • 协议可以继承一个或者多个其他协议,多个协议间用逗号隔开。
  • 当类或者枚举等遵循协议时,不仅仅要实现当前协议的方法,也需要实现所遵循协议继承的其他协议。
    • 代码示例:
protocol OneProtocol{    func sayOne()}// 协议的继承protocol TwoProtocol:OneProtocol{    func sayTwo()}class Person:TwoProtocol{    func sayOne() {        // 协议OneProtocol的方法    }    func sayTwo() {        // 协议TwoProtocol的方法    }}

协议的合成

  • 一个协议可以由多个协议采用protocol<NamedProtocol,GenderProtocol>这样的格式进行组合,称之为协议的合成(protocol composition)。
  • 协议合成并不会产生一个新的协议,而是将多个协议合成一个临时的协议,超出范围后立即失效。
  • 代码示例:
protocol NamedProtocol{    var name:String{get set}}protocol GenderProtocol{    var gender:String{get set}}protocol AgedProtocol{    var age:Int{get}}struct Person:NamedProtocol,GenderProtocol,AgedProtocol{    var name: String    var gender: String    var age: Int}func wishBirthday(celebrator:NamedProtocol & GenderProtocol){    print("姓名:\(celebrator.name),性别:\(celebrator.gender)")}var per = Person(name: "wang", gender: "man",age:20)wishBirthday(celebrator: per)// 形参celebrator的类型为protocol<NamedProtocol,GenderProtocol>,可以传入任何实现这两个协议的实例。即使此实例不仅仅遵循这两个协议。// swift3.0之后,protocol<NamedProtocol,GenderProtocol>被NamedProtocol & GenderProtocol替换。

检验协议的一致性

  • 使用is检验协议的一致性,使用as将协议类型向下转换为其他协议类型。
  • is操作符用来检查实例是否实现了某个协议。返回值true/false
  • as?返回一个可选值,当实例实现协议时,返回该协议类型;否则返回nil
  • as用以强制向下转化类型。
  • @objc用来表示协议时可选的,还可以表示暴露给Objective-C的代码,。
  • @objc型协议只对类有效,因此只能在类中检查协议的一致性。
    代码示例:
@objc protocol HasArea{    var area:Double{get}}class Circle:HasArea{    let pi = 3.1415927    var radius:Double    var area: Double{        return pi * radius * radius    }    init(radius:Double) {        self.radius = radius    }}class Country:HasArea{    var area: Double    init(area:Double) {        self.area = area    }}class Animal{    var legs:Int    init(legs:Int) {        self.legs = legs    }}let objects:[AnyObject] = [    Circle(radius: 20),    Country(area: 200),    Animal(legs: 10)]for object in objects {    var objectWithArea = object as? HasArea    if objectWithArea != nil {        print("\(objectWithArea)")        print("遵循了HasArea协议,\(object.area)")    }else{        print("没有遵循HasArea协议")    }}print("--------------------")for object in objects {    // 返回值 true/false    var objectWithArea = object is HasArea    if objectWithArea {        print("\(objectWithArea)")        print("遵循了HasArea协议,\(object.area)")    }else{        print("没有遵循HasArea协议")    }}/**打印结果:Optional(__lldb_expr_386.Circle)遵循了HasArea协议,Optional(1256.63708)Optional(__lldb_expr_386.Country)遵循了HasArea协议,Optional(200.0)没有遵循HasArea协议--------------------true遵循了HasArea协议,Optional(1256.63708)true遵循了HasArea协议,Optional(200.0)没有遵循HasArea协议*/

可选协议要求

  • 可选协议含有可选成员,其实现者可以选择是否实现这些成员。
  • 在协议中使用关键字optional关键字作为前缀来定义可选成员。
    • 代码示例:
@objc protocol HasArea{    @objc optional var area:Double{get}    var width:Double{get}}class Circle:HasArea{    let pi = 3.1415927    var radius:Double = 10.0    var width: Double = 20.0}
  • 可选类型只能在含有@objc前缀的协议中生效。而且@objc前缀的协议只能被类实现。
原创粉丝点击