//协议(Protocols)

import UIKit

/*协议(Protocols)

1.协议定义了一个蓝图,规定了用来实现某一特定任务或者功能的方法、属性,以及其他需要的东西

2.类、结构体或枚举都可以采纳协议,并为协议定义的这些要求提供具体实现。某个类型能够满足某个协议的要求,就可以说该类型“符合”这个协议。

3.除了采纳协议的类型必须实现的要求外,还可以对协议进行扩展,通过扩展来实现一部分要求或者实现一些附加功能,这样采纳协议的类型就能够使用这些功能。

协议定义语法:  protocol SomeProtocol { // 这里是协议的定义部分 }

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

class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {

// 这里是类的定义部分

}

属性要求:

1.协议可以要求采纳协议的类型提供特定名称和类型的实例属性或类型属性。协议不指定属性是存储型属性还是计算型属性,它只指定属性的名称和类型。

2.协议还指定属性是只读的还是可读可写的

3.如果协议要求属性是可读可写的,那么该属性不能是常量属性或只读的计算型属性。如果协议只要求属性是只读的,那么该属性不仅可以是只读的,如果代码需要的话,还可以是可写的

protocol SomeProtocol {

var mustBeSettable: Int { get set }     //表示属性是可读可写的

static var doesNotNeedToBeSettable: Int { get }        //类型属性、只读属性,static 关键字,类类型的还可以使用 class 关键字来声明类型属性

}

方法要求:

1.协议可以要求采纳协议的类型实现某些指定的实例方法或类型方法。这些方法作为协议的一部分,像普通方法一样放在协议的定义中,但是不需要大括号和方法体。可以在协议中定义具有可变参数的方法,和普通方法的定义方式相同。但是,不支持为协议中的方法的参数提供默认值。

2.在协议中定义类型方法的时候,总是使用 static 关键字作为前缀。当类类型采纳协议时,除了 static 关键字,还可以使用 class 关键字作为前缀

3.值类型的Mutating 方法要求:若需要在值类型的方法中修改方法所属的实例,将 mutating 关键字作为方法的前缀

构造器要求:协议可以要求采纳协议的类型实现指定的构造器

1.你可以在采纳协议的类中实现构造器,无论是作为指定构造器,还是作为便利构造器。无论哪种情况,你都必须为类的构造器实现标上 required 修饰符:

2.使用 required 修饰符可以确保所有子类也必须提供此构造器实现,从而也能符合协议

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

协议作为类型:

1.尽管协议本身并未实现任何功能,但是协议可以被当做一个成熟的类型来使用。

2.协议可以像其他普通类型一样使用,使用场景如下:

1.作为函数、方法或构造器中的参数类型或返回值类型

2.作为常量、变量或属性的类型

3.作为数组、字典或其他容器中的元素类型

委托(代理)模式:嵌套

1.委托是一种设计模式,它允许类或结构体将一些需要它们负责的功能委托给其他类型的实例。

2.委托模式的实现很简单:定义协议来封装那些需要被委托的功能,这样就能确保采纳协议的类型能提供这些功能。

3.委托模式可以用来响应特定的动作,或者接收外部数据源提供的数据,而无需关心外部数据源的类型

通过扩展采纳协议:

1.即便无法修改源代码,依然可以通过扩展令已有类型采纳并符合协议。扩展可以为已有类型添加属性、方法、下标脚本以及构造器,因此可以符合协议中的相应要求。通过扩展令已有类型采纳并符合协议时,该类型的所有实例也会随之获得协议中定义的各项功能。

2.当一个类型已经符合了某个协议中的所有要求,却还没有声明采纳该协议时,可以通过空扩展体的扩展来采纳该协议

协议类型的集合:协议类型可以在数组或者字典这样的集合中使用,所有采纳某协议的类型实例,虽然类型各不相同,但都是该协议类型

协议的继承:协议能够继承一个或多个其他协议,可以在继承的协议的基础上增加新的要求。协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔:

protocol InheritingProtocol: SomeProtocol, AnotherProtocol {

// 这里是协议的定义部分

}

类类型专属协议:在协议的继承列表中,通过添加 class 关键字来限制协议只能被类类型采纳,如果尝试让结构体或枚举类型采纳该协议,则会导致编译错误。

protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {

// 这里是类类型专属协议的定义部分

}

协议合成:有时候需要同时采纳多个协议,你可以将多个协议采用 protocol<SomeProtocol, AnotherProtocol> 这样的格式进行组合,称为 协议合成(protocol composition)。你可以在 <> 中罗列任意多个你想要采纳的协议,以逗号分隔

检查协议一致性:

1.你可以使用类型转换中描述的 is 和 as 操作符来检查协议一致性,即是否符合某协议,并且可以转换到指定的协议类型。

2.检查和转换到某个协议类型在语法上和类型的检查和转换完全相同:

is 用来检查实例是否符合某个协议,若符合则返回 true,否则返回 false。

as? 返回一个可选值,当实例符合某个协议时,返回类型为协议类型的可选值,否则返回 nil。

as! 将实例强制向下转换到某个协议类型,如果强转失败,会引发运行时错误。

可选的协议要求:

1.协议可以定义可选要求,采纳协议的类型可以选择是否实现这些要求。

2.在协议中使用 optional 关键字作为前缀来定义可选要求。

3.使用可选要求时(例如,可选的方法或者属性),它们的类型会自动变成可选的

4.协议中的可选要求可通过可选链式调用来使用,因为采纳协议的类型可能没有实现这些可选要求

5.可选的协议要求只能用在标记 @objc 特性的协议中。该特性表示协议将暴露给 Objective-C 代码,详情参见Using Swift with Cocoa and Objective-C(Swift 2.1)。即使你不打算和 Objective-C 有什么交互,如果你想要指定可选的协议要求,那么还是要为协议加上 @obj 特性。还需要注意的是,标记 @objc 特性的协议只能被继承自 Objective-C 类的类或者 @objc 类采纳,其他类以及结构体和枚举均不能采纳这种协议。

协议扩展:

1.协议可以通过扩展来为采纳协议的类型提供属性、方法以及下标脚本的实现。通过这种方式,你可以基于协议本身来实现这些功能,而无需在每个采纳协议的类型中都重复同样的实现,也无需使用全局函数

2.提供默认实现:可以通过协议扩展来为协议要求的属性、方法以及下标脚本提供默认的实现。如果采纳协议的类型为这些要求提供了自己的实现,那么这些自定义实现将会替代扩展中的默认实现被使用。

3.为协议扩展添加限制条件:在扩展协议的时候,可以指定一些限制条件,只有采纳协议的类型满足这些限制条件时,才能获得协议扩展提供的默认实现。这些限制条件写在协议名之后,使用 where 子句来描述

*/

protocol FullyNamed {

var fullName: String { get }

}

struct Person: FullyNamed {

var fullName: String

}

let john = Person(fullName: "John Appleseed")   // john.fullName 为 "John Appleseed"

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")   // ncc1701.fullName 是 "USS Enterprise"

//========================

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) % m)

return lastRandom / m

}

}

let generator = LinearCongruentialGenerator()

print("And another one: \(generator.random())") //每执行一次,lastRandom的值就被改变一次

print("And another one: \(generator.random())")

//=====================

class Dice {

let sides: Int

let generator: RandomNumberGenerator    //协议类型

init(sides: Int, generator: RandomNumberGenerator) {

self.sides = sides

self.generator = generator

}

func roll() -> Int {

return Int(generator.random() * Double(sides)) + 1

}

}

var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())

for _ in 1...5 {

print("Random dice roll is \(d6.roll())")

}

//=======================

protocol DiceGame {

var dice: Dice { get }

func play()

}

protocol DiceGameDelegate {

func gameDidStart(game: DiceGame)   //代理协议

func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll:Int)

func gameDidEnd(game: DiceGame)

}

class SnakesAndLadders: DiceGame {

let finalSquare = 25

let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())

var square = 0

var board: [Int]

init() {

board = [Int](count: finalSquare + 1, repeatedValue: 0)

board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02

board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

}

var delegate: DiceGameDelegate?

func play() {

square = 0

delegate?.gameDidStart(self)

gameLoop: while square != finalSquare {

let diceRoll = dice.roll()

delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)

switch square + diceRoll {

case finalSquare:

break gameLoop

case let newSquare where newSquare > finalSquare:

continue gameLoop

default:

square += diceRoll

square += board[square]

}

}

delegate?.gameDidEnd(self)

}

}

class DiceGameTracker: DiceGameDelegate {

var numberOfTurns = 0

func gameDidStart(game: DiceGame) {

numberOfTurns = 0

if game is SnakesAndLadders {

print("Started a new game of Snakes and Ladders")

}

print("The game is using a \(game.dice.sides)-sided dice")

}

func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {

++numberOfTurns

print("Rolled a \(diceRoll)")

}

func gameDidEnd(game: DiceGame) {

print("The game lasted for \(numberOfTurns) turns")

}

}

let tracker = DiceGameTracker()

let game = SnakesAndLadders()

game.delegate = tracker

game.play()

//===========================

protocol TextRepresentable {

var textualDescription: String { get }

}

extension Dice: TextRepresentable {     //扩展Dice类来采纳并符合协议

var textualDescription: String {

return "A \(sides)-sided dice"

}

}

let d12 = Dice(sides: 12,generator: LinearCongruentialGenerator())

print(d12.textualDescription)

extension SnakesAndLadders: TextRepresentable {

var textualDescription: String {

return "A game of Snakes and Ladders with \(finalSquare) squares"

}

}

print(game.textualDescription)

//==============

struct Hamster {

var name: String

var textualDescription: String {

return "A hamster named \(name)"

}

}

extension Hamster: TextRepresentable {}   //本身已经符合了协议的所有要求,可通过空扩展来采纳协议

let simonTheHamster = Hamster(name: "Simon")

let somethingTextRepresentable: TextRepresentable = simonTheHamster

print(somethingTextRepresentable.textualDescription)

//==================

let things: [TextRepresentable] = [game, d12, simonTheHamster]

for thing in things {

print(thing.textualDescription)

}

//========================

protocol PrettyTextRepresentable: TextRepresentable {

var prettyTextualDescription: String { get }

}

extension SnakesAndLadders: PrettyTextRepresentable {

//每个 PrettyTextRepresentable 类型同时也是 TextRepresentable 类型

//所以在 prettyTextualDescription 的实现中,可以访问 textualDescription 属性

var prettyTextualDescription: String {

var output = textualDescription + ":\n"

for index in 1...finalSquare {

switch board[index] {

case let ladder where ladder > 0:

output += "▲ "

case let snake where snake < 0:

output += "▼ "

default:

output += "○ "

}

}

return output

}

}

print(game.prettyTextualDescription)

//=============================

protocol Named {

var name: String { get }

}

protocol Aged {

var age: Int { get }

}

struct Person1: Named, Aged {

var name: String

var age: Int

}

func wishHappyBirthday(celebrator: protocol<Named, Aged>) {     //同时采纳多个协议

print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")

}

let birthdayPerson = Person1(name: "Malcolm", age: 21)

wishHappyBirthday(birthdayPerson)

//============================

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] = [    //它们都是类,它们的实例都可以作为 AnyObject 类型的值

Circle(radius: 2.0),

Country(area: 243_610),

Animal(legs: 4)

]

for object in objects {

if let objectWithArea = object as? HasArea {

print("Area is \(objectWithArea.area)")

} else {

print("Something that doesn't have an area")

}

}

//================================

@objc protocol CounterDataSource {

optional func incrementForCount(count: Int) -> Int

optional var fixedIncrement: Int { get }

}

class Counter {

var count = 0

var dataSource: CounterDataSource?

func increment() {

if let amount = dataSource?.incrementForCount?(count) {

count += amount

} else if let amount = dataSource?.fixedIncrement {

count += amount

}

}

}

class ThreeSource: NSObject, CounterDataSource {

let fixedIncrement = 3

}

var counter = Counter()

counter.dataSource = ThreeSource()

for _ in 1...4 {

counter.increment()

print(counter.count)

}

@objc class TowardsZeroSource: NSObject, CounterDataSource {

func incrementForCount(count: Int) -> Int {

if count == 0 {

return 0

} else if count < 0 {

return 1

} else {

return -1

}

}

}

counter.count = -4

counter.dataSource = TowardsZeroSource()

for _ in 1...5 {

counter.increment()

print(counter.count)

}

//=============================

//通过协议扩展,所有采纳协议的类型,都能自动获得这个扩展所增加的方法实现,无需任何额外修改:

extension RandomNumberGenerator {

func randomBool() -> Bool {

return random() > 0.5

}

}

let generator1 = LinearCongruentialGenerator()

print("Here's a random number: \(generator1.random())")

// 打印 “Here's a random number: 0.37464991998171”

print("And here's a random Boolean: \(generator1.randomBool())")

// 打印 “And here's a random Boolean: true”

//=======

extension CollectionType where Generator.Element: TextRepresentable {   //为协议的扩展添加限制条件

var textualDescription: String {

let itemsAsText = self.map { $0.textualDescription }

return "[" + itemsAsText.joinWithSeparator(", ") + "]"

}

}

转载于:https://www.cnblogs.com/susufufu/p/5705636.html

swift学习笔记之-协议相关推荐

  1. Swift学习笔记(4)使用UIImagePickerController实现从设备图片库和照相机获取图片

    Swift学习笔记(4)使用UIImagePickerController实现从设备图片库和照相机获取图片 设备图片库和照相机是图像的两个重要来源,使用UIKit中提供的图像选择器UIImagePic ...

  2. 【swift学习笔记】二.页面转跳数据回传

    上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...

  3. 【转】医疗业务学习笔记--DICOM协议的基础内容!!!!!!!!!!

    转自:医疗业务学习笔记--DICOM协议的基础内容 - 知乎 本文首发于"雨夜随笔"公众号,欢迎关注. DICOM协议是医疗领域对如何处理.存储.打印和传输医疗图片的一系列标准.D ...

  4. swift学习笔记《5》- 实用

    title: swift学习笔记<5>- 实用 date: 2016-09-21 21:39:00 categories: 学习笔记 Swift学习 tags: Swift 1.setVa ...

  5. Swift学习笔记笔记(一)Swift编程步骤数据类型

    一.实验目的: 掌握Swift编程方法. 掌握Swift数据类型. 二.实验原理: playground的界面与使用方法. 常量与变量的定义方法. 3.常量与变量的类型声明方法. 三.实验步骤及内容: ...

  6. 【转载】OpenStack Swift学习笔记

    免责声明:     本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系博主进行删除.     原文作者:崔炳华      原文地址:http://blog.csdn.net/i_ch ...

  7. OpenStack Swift学习笔记

    1       概述 OpenStack Object Storage(Swift)是OpenStack开源云计算项目的子项目之一.Swift的目的是使用普通硬件来构建冗余的.可扩展的分布式对象存储集 ...

  8. Swift学习笔记-协议(Protocols)

    1.0 翻译:geek5nan 校对:dabing1022 2.0 翻译:futantan 校对:小铁匠Linus 定稿:shanksyang 本页包含内容: 协议的语法(Protocol Synta ...

  9. 【Swift学习笔记00】——enumeration枚举类型遵循协议protocol

    Apple官方文档:The Swift Programming Language Protocols and Extensions一节的小节练习,要求自行定义一个enumeration枚举类型,并且遵 ...

最新文章

  1. 一文读懂马斯克展示脑机接口:硬币大小芯片植入猪脑 实时读取猪脑信息
  2. leetcode—Best Time to Buy and Sell stocks III
  3. SlidingMenu实现侧滑
  4. zzuliOJ 2536: 绿绿学姐与AI 1
  5. echarts树状图点击展开子节点_CPU眼里的结构设备树节点及属性详解
  6. 私有属性和方法-子类对象不能直接访问
  7. linux 不同ip 相同mac arp,linux – nmap和arp-scan不一致的IP-MAC结果
  8. 面试干货 | Java 能否自定义一个类叫 java.lang.System?
  9. python输入三个整数_python笔记3:依次输入3个数排序打
  10. hbase shell删除一行_HBase安装phoenix实战shell操作
  11. 快手用户公开视频下载代码
  12. cpu型号怎么看服务器,看不懂CPU?学会看CPU只要五分钟
  13. Unity游戏开发图片纹理压缩方案
  14. linux 常用解压、压缩命令合集——筑梦之路
  15. mysql group 查询的替代_mysql group_concat替代或多行作为列
  16. 使用css实现渐变色背景
  17. 不同网络环境下监控视频统一汇聚集中管理方案介绍
  18. Vue-vue-cli的安装
  19. [Python] 制作超级玛丽游戏
  20. 关于字符集GB2312/GBK/GB18030的区别

热门文章

  1. input输入框禁止自动补全和下拉提示
  2. 视频课程-1小时上手 Spring Boot 及 达梦数据库 做数据展示后端
  3. Java工作笔记-使用Maven创建多模块项目
  4. Qt文档阅读笔记|Qt实践| HTTPS知识点-获取某站点SSL证书
  5. C++设计模式-职责链模式
  6. Spring Boot笔记-接收RabbitMQ队列中的消息
  7. C++ opengl 放置摄像机
  8. Qt工作笔记-多线程时间服务应用
  9. oracle ash介绍,Oracle ---- 性能调查之ASH(一)
  10. js符号输入不可用_JS 控制非法字符的输入代码