美文网首页
Swift_Protocol_Base

Swift_Protocol_Base

作者: YoNotes | 来源:发表于2018-02-25 15:47 被阅读4次
  • 协议:代理设计模式
  • 协议能够被 类、枚举、结构体 实现,满足协议要求的类、枚举、结构体被称为协议的是实现者

①Protocol语法

❶格式

  • 在类、枚举、结构体的名称后加上协议名称,中间以冒号(:)分隔,即可实现协议,当实现多个协议时,多个协议间用逗号(,)隔开
  • 类含有父类,则应当将父类放在所有的协议之前
class 类名 : 协议1 , 协议n{
}
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)") // 90
print("\(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 //Off
light.toggle()  // On

struct 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)") // 3
LIGHT.toggle()
print("\(LIGHT.two)") // 20

❺使用协议规范构造函数

  • 协议可以规定必须实现指定的构造函数,比如一些类中必须要求实现init构造函数,这样就可以制造一个协议,让实现协议的类必须实现该构造函数。
  • 实现构造协议的类,必须使用关键字required
protocol TwoProtocol{
    init(twoArgument:Int)
}
class two:TwoProtocol{
    required init(twoArgument: Int) {
    }
}
  • 父类中存在与协议内相同的构造方法,则子类在实现构造方法时,需要同时使用关键字required和override
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的方法
    }
}

❶protocolComposition协议的合成

  • 一个协议可以由多个协议采用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
}

参考01

相关文章

  • Swift_Protocol_Base

    协议:代理设计模式 协议能够被 类、枚举、结构体 实现,满足协议要求的类、枚举、结构体被称为协议的是实现者 ①Pr...

网友评论

      本文标题:Swift_Protocol_Base

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