//协议(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(", ") + "]"

}

}

swift学习笔记之-协议的更多相关文章

  1. Swift 学习笔记(面向协议编程)

    在Swift中协议不仅可以定义方法和属性,而且协议是可以扩展的,最关键的是,在协议的扩展中可以添加一些方法的默认实现,就是在协议的方法中可以实现一些逻辑,由于这个特性,Swift是可以面向协议进行编程 ...

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

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

  3. Swift学习笔记(一)搭配环境以及代码运行成功

    原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...

  4. Objective-C学习笔记 利用协议实现回调函数

    来源:http://mobile.51cto.com/iphone-278354.htm Objective-C学习笔记 利用协议实现回调函数是本文要介绍的内容,主要是实现一个显示文字为测试的视图,然 ...

  5. swift学习笔记4——扩展、协议

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  6. swift学习笔记5——其它部分(自动引用计数、错误处理、泛型...)

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  7. 记录:swift学习笔记1-2

    swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...

  8. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  9. swift学习笔记2——函数、闭包

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

随机推荐

  1. JavaScript禁用页面刷新

    JavaScript禁用页面刷新代码如下: //禁用F5刷新 document.onkeydown = function () { if (event.keyCode == 116) { event. ...

  2. 构建自己的PHP框架--搭建基本结构

    首先,我们来说一下,为什么要创建自己的框架? 为什么要创建自己的框架呢?如果你跟周围的人讨论,每个人都会告诉你重复发明轮子是一件糟糕的事情,你最好选择一个已有的框架,忘掉“创建自己的框架”这种想法.大 ...

  3. javascript学习4

    JavaScript Date(日期)对象 日期对象用于处理日期和时间. JavaScript Date(日期)对象 实例 返回当日的日期和时间 如何使用 Date() 方法或者当日的日期. getT ...

  4. 【Android】Volley做网络请求的几种用法

    前言: 最近在将自己写的烂代码重构,以前使用的网络请求全是基于apache的HttpClient,简单使用还好,使用多了发现重复代码太多,而且每次使用都很繁琐,因此在网上找了半天网络请求的相关类库,最 ...

  5. tomcat组成及工作原理

    1 - Tomcat Server的组成部分 1.1 - Server A Server element represents the entire Catalina servlet containe ...

  6. Windows Azure Affinity Groups (3) 修改虚拟网络地缘组(Affinity Group)的配置

    <Windows Azure Platform 系列文章目录> 本文介绍的是国内使用世纪互联运维的Azure China 在笔者之前的文章中,我们知道现在微软官方不建议使用Affinity ...

  7. 大数据下的Distinct Count(一):序

    在数据库中,常常会有Distinct Count的操作,比如,查看每一选修课程的人数: select course, count(distinct sid) from stu_table group ...

  8. tornado--SESSION框架,一致性hash,分布式存储

    预备知识 tornado框架session要自己写 cookie存储在客户端浏览器上,session数据放在服务器上 session依赖cookie 扩展tornado,返回请求前自定义session ...

  9. CSS魔法堂:你真的理解z-index吗?

    一.前言 假如只是开发简单的弹窗效果,懂得通过z-index来调整元素间的层叠关系就够了.但要将多个弹窗间层叠关系给处理好,那么充分理解z-index背后的原理及兼容性问题就是必要的知识储备了.本文作 ...

  10. 简单认识C#

    C#浅解众所周知c#是微软推出的一款完全没面向对象的编程语言,那么对象是什么?在现实生活中人们一提到对象首先想到的就是“情侣”!但是在我们的程序中对象是什么? 在程序中个能够区别于其他事物的独立个体我 ...