//协议(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. AngularJs ui-router 路由的简单介绍

    之前有写过一篇关于Angular自带的路由:ngRoute.今天来说说Angular的第三方路由:ui-router.那么有人就会问:为什么Angular有了自带的路由,我们还需要用ui-router ...

  2. Hadoop官方文档翻译—— YARN ResourceManager High Availability 2.7.3

    ResourceManager High Availability (RM高可用) Introduction(简介) Architecture(架构) RM Failover(RM 故障切换) Rec ...

  3. Android自动连接指定的wifi,免密码或指定密码

    一.运行时的状态 遇到一个这样的要求:“不进行扫描操作,怎么对指定的免密码WIFI进行连接(之前没有连接过)”,于是动手写了一个Demo,如图所示未连接成功时的状态,第一个编辑框让用户输入SSID,第 ...

  4. nodejs 调试 node-inspector包

    nodejs  调试调试比较麻烦,让习惯了用chrome浏览器调试的前端同学来说有点不适用  node-inspector这个包让我们可以在chrome上像调试前端代码一样来调试nodejs 1.全局 ...

  5. UWP开发入门(二十一)——保持Ui线程处于响应状态

    GUI的程序有时候会因为等待一个耗时操作完成,导致界面卡死.本篇我们就UWP开发中可能遇到的情况,来讨论如何优化处理. 假设当前存在点击按钮跳转页面的操作,通过按钮打开的新页面,在初始化过程中存在一些 ...

  6. 八、RFCOMM

    1.      RFCOMM 先来看看RFCOMM在协议栈层次体系中的位置.从下图可以看出RFCOMM处于传输层.与AVCTP,TCS-BIN处于同一层次.处于其上层的会话层中的OBEX,SPP等大部 ...

  7. BZOJ1088扫雷Mine 解析报告

    1088: [SCOI2005]扫雷Mine Description 相信大家都玩过扫雷的游戏.那是在一个n*m的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了,“余”人国流行起了一种简单的扫 ...

  8. C#--析构函数

  9. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)

    这个系列已经写了6篇,链接地址如下: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Auto ...

  10. Bootstrap学习笔记系列5------Bootstrap图片显示

    通过添加一下的class来实现bootstrap对图片的支持 img-round 通过border-radius:6px 来获得图片圆角 img-circle 通过border-radius:50%来 ...