《swift2.0 官方教程中文版》 第2章-22协议
import Foundation
/*协议的语法********************************************************/ //protocol SomeProtocol { // // 协议内容 //}
//struct SomeStructure: FirstProtocol,AnotherProtocol { // // 结构体内容 //}
//如果类在遵循协议的同时拥有父类,应该将父类名放在协议名之前,以逗号分隔。 //class SomeClass: SomeSuperClass,FirstProtocol,AnotherProtocol { // // 类的内容 //}
/*对属性的规定********************************************************/ //协议中的通常用var来声明属性,在类型声明后加上 { set get } 来表示属性是可读可写的,只读属性则用 { get } 来表示。 protocol SomeProtocol { var mustBeSettable: Int {get set} var doesNotNeedToBeSettable: Int {get} }
//在协议中定义类属性(type property)时,总是使用 static 关键字作为前缀。当协议的遵循者是类时,可以使用 ass 或 static 关键字来声明类属性,但是在协议的定义中,仍然要使用 static 关键字。 protocol AnotherProtocol { static var someTypeProperty: Int {get set} }
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") print("ncc1701.fullName is (ncc1701.fullName)") // ncc1701.fullName is "USS Enterprise"
/*对方法的规定********************************************************/ //protocol SomeProtocol{ // static func someTypeMethod() //}
protocol RandomNumberGenerator { func random() -> Double }
//协议并不在意每一个随机数是怎样生成的,它只强调这里有一个随机数生成器。 //如下所示,下边的是一个遵循了 协议的类。该类实现了一个叫做线性同余生成器(lin ear congruential generator)的伪随机数算法。 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("Here's a random number: (generator.random())") // 输出 : "Here's a random number: 0.37464991998171" print("And another one: (generator.random())") // 输出 : "And another one: 0.729023776863283"
/*对Mutating方法的规定********************************************************/ //有时需要在方法中改变它的实例。例如,值类型(结构体,枚举)的实例方法中,将 mutating 关键字作为函数的前 缀,写在 func之前,表示可以在该方法中修改它所属的实例及其实例属性的值 //注意: //用类实现协议中的 mutating 方法时,不用写 mutating 关键字;用结构体,枚举实现协议中的 mutating 方法 时,必须写 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() //lightSwitch 现在的值为 .On
/*对构造器的规定********************************************************/ protocol SomeProtocol2 { init(someParameter: Int) } class SomeClass: SomeProtocol2 { required init(someParameter: Int) { //构造器实现 } } //使用 required 修饰符可以保证:所有的遵循该协议的子类,同样能为构造器规定提供一个显式的实现或继承实 现。 //如果类已经被标记为 final,那么不需要在协议构造器的实现中使用 required 修饰符。因为final类不能有子 类。 //如果一个子类重写了父类的指定构造器,并且该构造器遵循了某个协议的规定,那么该构造器的实现需要被同时 标示 required 和 override 修饰符 //protocol SomeProtocol { // init() //} //class SomeSuperClass { // init() { // // 构造器的实现 // } //} //class SomeSubClass: SomeSuperClass,SomeProtocol { // // 因为遵循协议,需要加上"required"; 因为继承自父类,需要加上"override" // required override init() { // // 构造器实现 // } //}
/*协议类型********************************************************/ //协议可以像其他普通类型一样使用,使用场景: //? 作为函数、方法或构造器中的参数类型或返回值类型 //? 作为常量、变量或属性的类型 //? 作为数组、字典或其他容器中的元素类型 //协议是一种类型,因此协议类型的名称应与其他类型(Int,Double,String)的写法相同,使用大写字母开头的 驼峰式写法 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 } } //Dice 的实例含有 sides 和 generator 两个属性,前者是整型,用来表示骰子有几个面,后者为骰子提供一个随机数生成器。 var d6 = Dice(sides: 6,generator: LinearCongruentialGenerator()) for _ in 1...5 { print("Random dice roll is (d6.roll())") } //输出结果 //Random dice roll is 3 //Random dice roll is 5 //Random dice roll is 4 //Random dice roll is 5 //Random dice roll is 4
/*委托(代理)模式********************************************************/ //委托是一种设计模式,它允许 类 或 结构体 将一些需要它们负责的功能 交由(委托) 给其他的类型的实例。委托模 式的实现很简单: 定义协议来封装那些需要被委托的函数和方法,使其 遵循者 拥有这些被委托的 函数和方法 。委托模式可以用来响应特定的动作或接收外部数据源提供的数据,而无需要知道外部数据源的类型信息。 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() // Started a new game of Snakes and Ladders // The game is using a 6-sided dice // Rolled a 3 // Rolled a 5 // Rolled a 4 // Rolled a 5 // The game lasted for 4 turns
/*在扩展中添加协议成员********************************************************/ //即便无法修改源代码,依然可以通过扩展(Extension)来扩充已存在类型(译者注: 类,结构体,枚举等)。扩展可以为已存在的类型添加属性,方法,下标脚本,协议等成员。 protocol TextRepresentable{ func asText() -> String }
extension Dice: TextRepresentable { func asText() -> String { return "A (sides)-sided dice" } }
let d12 = Dice(sides: 12,generator: LinearCongruentialGenerator()) print(d12.asText()) // 输出 "A 12-sided dice"
extension SnakesAndLadders: TextRepresentable { func asText() -> String { return "A game of Snakes and Ladders with (finalSquare) squares" } } print(game.asText()) // 输出 "A game of Snakes and Ladders with 25 squares"
/*通过扩展补充协议声明********************************************************/ //当一个类型已经实现了协议中的所有要求,却没有声明为遵循该协议时,可以通过扩展(空的扩展体)来补充协议声 明: struct Hamster { var name: String func asText() -> String { return "A hamster named (name)" } } extension Hamster: TextRepresentable {} //从现在起,Hamster 的实例可以作为 TextRepresentable 类型使用 let simonTheHamster = Hamster(name: "Simon") let somethingTextRepresentable: TextRepresentable = simonTheHamster print(somethingTextRepresentable.asText()) // 输出 "A hamster named Simon"
/*集合中的协议类型********************************************************/ //协议类型可以在集合使用,表示集合中的元素均为协议类型,下面的例子创建了一个类型为TextRepresentable的数组: let things: [TextRepresentable] = [game,d12,simonTheHamster] for thing in things { print(thing.asText()) } // A game of Snakes and Ladders with 25 squares // A 12-sided dice // A hamster named Simon
/*协议的继承********************************************************/ //协议能够继承一个或多个其他协议,可以在继承的协议基础上增加新的内容要求。协议的继承语法与类的继承相 似,多个被继承的协议间用逗号分隔: //protocol InheritingProtocol: SomeProtocol,AnotherProtocol { // // 协议定义 //} protocol PrettyTextRepresentable: TextRepresentable { func asPrettyText() -> String }
extension SnakesAndLadders: PrettyTextRepresentable { func asPrettyText() -> String { var output = asText() + ":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 } } //? 当从数组中取出的元素的值大于0时,用▲表示 //? 当从数组中取出的元素的值小于0时,用 ▼ 表示 //? 当从数组中取出的元素的值等于0时,用 ○ 表示 print(game.asPrettyText()) // A game of Snakes and Ladders with 25 squares: // ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○
/*类专属协议********************************************************/ //你可以在协议的继承列表中,通过添加 class 关键字,限制协议只能适配到类(class)类型。(结构体或枚举不能 遵循该协议)。该 class 关键字必须是第一个出现在协议的继承列表中,其后,才是其他继承协议。 //protocol SomeClassOnlyProtocol: class,SomeInheritedProtocol { // // class-only protocol definition goes here //}
/*协议合成********************************************************/ //有时候需要同时遵循多个协议。你可以将多个协议采用 protocol<SomeProtocol,AnotherProtocol> 这样的格 式进行组合,称为 协议合成(protocol composition) 。 protocol Named { var name: String{get} } protocol Aged { var age: Int{get} } struct Person2: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 = Person2(name:"Malcolm",age:21) wishHappyBirthday(birthdayPerson)
/*检验协议的一致性********************************************************/ //可以使用 is 和 as 操作符来检查是否遵循某一协议或强制转化为某一类型。 //? is 操作符用来检查实例是否 遵循 了某个 协议 //? as? 返回一个可选值,当实例 遵循 协议时,返回该协议类型;否则返回 nil //? as 用以强制向下转型,如果强转失败,会引起运行时错误。 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} }
//Circle,Country,Animal 并没有一个相同的基类,然而,它们都是类,它们的实例都可以作为 类型的变量,存储在同一个数组中: let objects:[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") } } // Area is 12.5663708 // Area is 243610.0 // Something that doesn't have an area
/*对可选协议的规定********************************************************/ //可选协议只能在含有 @objc 前缀的协议中生效。且 @objc 的协议只能被 类 遵循 这个前缀表示协议将暴露给Objective-C代码,详情参见 Using Swift with Cocoa and Objective-C 。即使你 不打算和Objective-C有什么交互,如果你想要指明协议包含可选属性,那么还是要加上 @obj 前缀 @objc protocol CounterDataSource{ optional func incrementForCount(count: Int) -> Int optional var fixedIncrement: Int {get} } //CounterDataSource 中的属性和方法都是可选的,因此可以在类中声明都不实现这些成员,尽管技术上允许这样做,不过最好不要这样写。 //@objc 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 // } // } //}
//@objc class ThreeSource: CounterDataSource { // let fixedIncrement = 3 //}
/*协议扩展********************************************************/ //使用扩展协议的方式可以为遵循者提供方法或属性的实现。通过这种方式,可以让你无需在每个遵循者中都实现一次,无需使用全局函数,你可以通过扩展协议的方式进行定义。 extension RandomNumberGenerator{ func randomBool() -> Bool{ return random() > 0.5 } } let generator2 = LinearCongruentialGenerator() print("Here's a random number: (generator2.random())") // 输出 "Here's a random number: 0.37464991998171" print("And here's a random Boolean: (generator2.randomBool())") // 输出 "And here's a random Boolean: true"
extension PrettyTextRepresentable { func asPrettyText() -> String { return asText() } }
//extension CollectionType where Generator.Element: TextRepresentable { // func asList() -> String { // return "(" + ",".join(map({$0.asText()})) + ")" // } //} // //let murrayTheHamster = Hamster(name: "Murray") //let morganTheHamster = Hamster(name: "Morgan") //let mauriceTheHamster = Hamster(name: "Maurice") //let hamsters = [murrayTheHamster,morganTheHamster,mauriceTheHamster] //print(hamsters.asList()) // 输出 "(A hamster named Murray,A hamster named Morgan,A hamster named Maurice)" (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |