寒城攻略:Listo 教你 25 天学会 Swift 语言 - 23 Protocols
//*********************************************************************************************** //1.Protocols(协议) //_______________________________________________________________________________________________ //介绍 //协议用于统一方法和属性的名称,而不是实现任何功能。协议能被类,枚举,结构体实现,满足协议要求的类,枚举,结构体被称为协议的遵循者 //协议需要提供协议指定的成员,如属性,方法,操作符,下标等
//*********************************************************************************************** //2.Protocol Syntax(协议语法) //_______________________________________________________________________________________________ //代码演示协议的定义方法和调用方法 protocol SomeProtocol{ //协议的定义,协议名需要需要大写 //协议内容 }
struct SomeStructure: SomeProtocol{ //给对象添加协议 //结构体的内容 }
//当某个对象含有父类的同时并实现了协议,应当把父类放在所有的协议之前 /* class SomeClass: SuperClass,SomeProtocol{ //类的内容 } */
//3.Property Requirements(属性要求) //协议能够要求其遵循者必须包含一些特定名称和类型的实例属性或者类属性,也能够要求属性的设置权限和访问权限,但它不要求属性是存储属性还是计算型属性
//实例代码演示协议的属性的完善 protocol SomeProtocol1{ var musBeSettable: Int {get set} //通常采用 var 关键字将属性声明为变量,在属性声明后面加上 {get set} 表明属性为可读写的。{get} 用来表示属性为可读的 var doesNotNeedToBeSettable: Int {get} }
protocol AnotherProtocol{ class var someTypeProperty: Int {get set} //用类来实现协议属性的时候,需要在类成员前面加上 class 关键字,用结构体实现协议属性时,用 static 引导 }
protocol FullyNamed{ var fullName: String {get} }
//协议的遵守代码实例1(结构体遵守协议) struct Person: FullyNamed{ var fullName: String //FullyNamed 协议含有 fullName 属性。因此其遵循者必须含有一个名为 fullName,类型为 String 的可读属性 }
let john = Person(fullName: "Listo Han")
//协议的遵守代码实例2(类遵守协议) class Starship: FullyNamed{ var prefix: String? var name: String init(name: String,prefix: String? = nil){ self.name = name self.prefix = prefix } var fullName: String{ //Starship 类遵循了 FullyNamed 协议,因此这个类必须包含名为 fullName 属性 return (prefix != nil ? prefix! + " " : " ") + name } } var ncc1701 = Starship(name: "Listo",prefix: "USS")
//4.Method Requirements(方法要求) //协议能够要求其遵循者必备某些特定的实例方法和类方法,协议方法的声明与普通方法声明相似,只是不需要方法的内容
//实例代码演示协议中方法的设置 protocol SomeProtoco2l{ class func someTypeMethod() //用 class 引导,表示协议中的成员为类成员 }
protocol RandomNumberGenerator{ //RandomNumberGenerator 协议要求其遵循者必须拥有一个名为 random,返回值类型为Double 的实例方法 func random() -> Double }
//协议的遵守实例 class LinerCongruentialGenerator: RandomNumberGenerator{ //LinerCongruentialGenerator 类遵守协议 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 = LinerCongruentialGenerator() println("Here's a random number: (generator.random())") println("And another one : (generator.random())")
//5.Mutating Method Requirements(突变方法要求) //能在方法或者函数内部改变实例类型的方法成为突变方法,在值类型中的函数前添加前缀 mutating 关键字来表示该函数允许改变该实例和其属性的类型
//实例代码演示协议中的突变方法设置 protocol Togglable{ mutating func toggle() //为值类型设置方法 }
//协议的实例遵守 enum OnOffSwitch: Togglable{ case Off,On mutating func toggle() { switch self{ case Off: self = On case On: self = Off } } } var lightSwitch = OnOffSwitch.Off lightSwitch.toggle()
//6.Protocols as Types(协议类型) //协议本身不实现任何功能,但是我们可以把它当作类型来使用 /* 使用协议的场景: 1.作为函数,方法或者构造器中的参数类型来使用 2.作为常量,变量,属性的类型 3.作为数组,字典或者其他容器中的元素类型 //定义一个 Dice 类以备后用(协议做属性类型,协议做构造器参数类型) class Dice{ let sides: Int let generator: RandomNumberGenerator //Dice 含有 sides 和 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: LinerCongruentialGenerator()) for _ in 1...5{ println("Random dice roll is (d6.roll())") }
//7.Delegation(委托代理模式) //委托是一种模式,它允许类或结构体将一些需要他们负责的功能交由给其他的类型 //委托模式的实现很简单:定义协议来封装那些需要被委托的函数和方法,使其遵循者拥有这些被委托的函数和方法
//实例代码演示委托 protocol DiceGame{ //DiceGame 为实现游戏的协议 var dice: Dice {get} func paly() } protocol DiceGameDelegate{ //DiceGameDelegate 为跟踪游戏过程 func gameDidStart(game: DiceGame) func game(game: DiceGame,didStartNewTurnWithDiceRoll diceRoll: Int) func gameDidEnd(game: DiceGame) }
class SnakesAndLadders: DiceGame{ //定义 SnakesAndLadders 遵守协议 DiceGame let finalSquare = 25 let dice = Dice(sides: 6,generator: LinerCongruentialGenerator()) //满足协议 DiecGame 的属性
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[24] = -08 board[14] = -10 board[19] = -11 board[22] = -02 } var delegate: DiceGameDelegate? //因为 delegate 是一个遵循 DiceGameDelegate 协议的可选属性类型,因此在 play()方法中使用了可选链来调用委托方法。若 delegate 属性为 nil, 则委托调用优雅地失效。若 delegate 不为nil,则委托方法被调用 func paly(){ //满足协议 DiceGame 的方法 delegate?.gameDidEnd(self) //通过代理使用 DiceGameDelegate 协议中的方法 delegate?.game(self,didStartNewTurnWithDiceRoll: 1) delegate?.gameDidStart(self) } }
class DiceGameTracker: DiceGameDelegate{ //DiceGameTracker 实现了 DiceGameDelegate 协议的方法要求 var numberOfTurns = 0 func gameDidStart(game: DiceGame) { //满足协议 DiceGameDelegate 的方法 if game is SnakesAndLadders{ println("Started a new game of Snakes and Ladders") } println("The game is using a (game.dice.sides) - sided dice") } func game(game: DiceGame,didStartNewTurnWithDiceRoll diceRoll:Int){ //的方法 ++numberOfTurns println("Rolled a (diceRoll)") } func gameDidEnd(game: DiceGame){ //满足协议的方法 println("The game lasted for (numberOfTurns) turns") } }
let tracker = DiceGameTracker() let game = SnakesAndLadders() game.delegate = tracker //给 SnakesAndLadders 类型的实例的 .delegate 赋值让它不为 nil 时,便可以在 SnakesAndLadders 实例中使用 DiceGameDelegate 协议内的方法 game.paly()
//8.Adding Protocol Conformance with an Extension(在扩展中添加协议成员) //即使无法修改源代码,依然可以通过扩展来扩充已存在类型
//实例代码演示在扩展中添加协议成员 protocol TextRepresentable{ //定义一个协议 func asText() -> String }
extension Dice: TextRepresentable{ //给 Dice 协议扩展功能 func asText() -> String{ return "A (sides) - side dice" } }
let d12 = Dice(sides: 12,generator: LinerCongruentialGenerator()) println(d12.asText()) //这是我们可以使用扩展过后的协议的方法
//通过扩展补充协议声明 struct Hamster{ var name: String func asText() -> String{ return "A hamster named (name)" } } extension Hamster: TextRepresentable{} //当一个类型已经实现了协议中的所有要求,却没有声明时,可以通过扩展来补充协议声明
let simonTheHamster = Hamster(name: "Simon") let somethingTextRepresentable: TextRepresentable = simonTheHamster println(somethingTextRepresentable.asText())
//9.Collections of Protocol Types(集合中的协议类型) //协议可以被集合使用,表示集合中的元素均为协议类型 let things: [TextRepresentable] = [d12,simonTheHamster] for thing in things{ println(thing.asText()) }
//10.Protocol Inheritance(协议的继承) //协议能够继承一到多个其他的协议,语法与类的继承相似
//实例代码演示协议的继承 protocol PrettyTextRepresentable: TextRepresentable{ //PrettyTextRepresentable 协议继承l了TextRepresentable 协议,遵循 PrettyTextRepresentable 协议的同时,也需要遵循 TextRepresentable 的协议 func asPrettyText() -> String }
extension SnakesAndLadders: PrettyTextRepresentable { //用扩展为 SnakesAndLadders 遵循PrettyTextRepresentable 协议 func asPrettyText() -> String { //遵守 PrettyTextRepresentable 协议中的方法 var output = "Hello" + ":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 } func asText() -> String{ //遵守 TextRepresentable 协议中的方法 return "Listo" } } println(game.asPrettyText()) println(game.asText())
//11.Protocol Composition(协议的合成) //实例代码演示协议的合成 protocol Named{ //Named 协议包含 String 类型的 name 属性 var name: String {get} } protocol Aged{ //Aged 协议包含 Int 类型的 age 属性 var age: Int {get} } struct Person1: Named,Aged{ //Person 结构体遵循了这两个协议 var name: String var age: Int }
func wishHappyBirthday(celebrator: protocol<Named,Aged>){ //wishHappyBirthday 函数的形参 celebrator 的类型为 protocol<Named,Aged>。可以传入任 意遵循这两个协议的类型的实例 println("Happy birthday (celebrator.name) - you're (celebrator.age)") } let birthdayPerson = Person1(name: "Pin",age: 21) wishHappyBirthday(birthdayPerson)
//12.Checking for Protocol Conformance(检查协议的一致性) //使用 is 检查协议的一致性,使用 as 将协议类型向下转换为其他的协议类型(is 判断某个类型是否遵守协议,as? 返回一个可选值,当实例遵守协议时,返回协议类型,否则为 nil,as 用以强制向下转化
//实例代码演示检查协议的一致性 @objc protocol HasArea{ //这里的 @objc 用来表示协议是可选的,@objc 型协议只对类有效,只能检查类中协议的一致性 var area: Double {get} } class Circle: HasArea { let pi = 3.1415927 var radius: Double var area: Double { //Circle 遵守协议 HasArea,并且把 area 写成计算型属性 return pi * radius * radius } init(radius: Double) { self.radius = radius } } class Country: HasArea { //Country 遵守协议 HasArea,并且把 area 写成存储型属性 var area: Double init(area: Double) { self.area = area } } class Animal{ //Animal 不遵守任何协议 var legs: Int init(legs: Int) { self.legs = legs } }
let objects: [AnyObject] = [ //Circle,Country,Animal 并没有相同的父类,所以使用 Anyobject 来装载他们的实例 Circle(radius: 2.0), Country(area: 242_455), Animal(legs: 4) ]
for object in objects{ if let objectWithArea = object as? HasArea{ //当数组中的元素遵循 HasArea 协议时,通过 as?操作符将其可选绑定(optional binding)到 objectWithArea 常量上 println("Area is (objectWithArea.area)") } else{ println("Something that doesn't have an area") } }
//13.Optional Protocol Requirements(可选协议要求) //可选协议含有可选成员,其遵循者可以选择是否实现这个可选成员,在协议中使用 @optional 关键字作为前缀来定义可选成员
//实例代码演示可选协议的使用 @objc protocol CounterDataSource{ optional func incrementForCount(count: Int) -> Int //定义协议可选方法 optional var fixedIncrement: Int {get} //定义协议可选属性 } @objc class Counter{ var count = 0 var dataSource: CounterDataSource? func increment(){ if let amount = dataSource?.incrementForCount?(count){ //由于 dataSource 可能为 nil,因此在 dataSource 后边加上了?标记来表明只在 dataSource 非空时才去调用 incrementForCount 方法,即使 dataSource 存在,但是也无法保证其是否实现了 incrementForCount 方法,因此在 incrementForCount 方法后边也加有?标记 count += amount } else if let amount = dataSource?.fixedIncrement?{ //当 incrementForCount 不能被调用时,尝试使用可选属性 fixedIncrement 来代替(代理) count += amount } } }
class ThreeSource: CounterDataSource{ //ThreeSource 实现了 CounterDataSource 协议 let fixedIncrement = 3 } var counter = Counter() counter.dataSource = ThreeSource() //使用 ThreeSource 作为数据源开实例化一个 Counter for _ in 1...4{ counter.increment() println(counter.count) }
class TowardsZeroSource: CounterDataSource{ //TowardsZeroSource 实现了 CounterDataSource 协议中的 incrementForCount 方法 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{ println(counter.count) }
转载:http://blog.csdn.net/u013096857/article/details/37872299 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |