Swift_学习笔记_协议
来源:互联网 发布:网络上的唱歌比赛 编辑:程序博客网 时间:2024/06/04 17:52
- 协议:代理设计模式
- 协议能够被类、枚举、结构体实现,满足协议要求的类、枚举、结构体被称为协议的是实现者。
协议的语法
- 在类、枚举、结构体的名称后加上协议名称,中间以冒号(:)分隔,即可实现协议,当实现多个协议时,多个协议间用逗号(,)隔开。
- eg.
class 类名:协议1,协议n{}
- eg.
- 如果类含有父类,则应当将父类放在所有的协议之前。
- eg.
class 类名:父类,协议1,协议n{}
- eg.
属性的要求
- 无论声明的属性为类属性还是对象属性,均需要在属性声明后加上
{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) { }}
- 如果父类中存在与协议内相同的构造方法,则子类在实现构造方法时,需要同时使用关键字
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的方法 }}
协议的合成
- 一个协议可以由多个协议采用
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
前缀的协议只能被类实现。
阅读全文
0 0
- Swift_学习笔记_协议
- Swift_学习笔记_基础知识
- Swift_学习笔记_类
- Swift_学习笔记_继承
- Swift_学习笔记_泛型
- Swift_学习笔记_字符串、数组、字典
- Swift_学习笔记_自动引用计数
- Swift_学习笔记_类型转换
- Swift_学习笔记_运算符重载
- Swift_学习笔记_闭包
- Swift_学习笔记_调用ObjectiveC方法
- Swift_学习笔记_控制语句和函数
- Swift_学习笔记_枚举和结构体
- Swift_协议
- modbus协议_笔记
- HTTP协议_笔记
- TCP_IP协议详解学习笔记_卷1_第17-18章_TCP协议
- TCP_IP协议详解学习笔记_卷1_第11章_UDP协议
- Elasticsearch索引。
- 05-Vue入门系列之Vue实例详解与生命周期
- 一致性哈希算法与Java实现
- openssl交叉编译问题
- window.print打印指定div指定网页指定区域的方法
- Swift_学习笔记_协议
- HTTP中get和post区别
- android x86 系统升级
- 用 CNTK 搞深度学习 (一) 入门
- 标准输入输出重定向
- Linux-IIC驱动(4)-自编IIC设备驱动程序
- ionic cordova开发android应用的坑
- iOS下无法触发focus事件的问题
- 一篇博客让你了解Material Design的使用