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:[@H_157_4036@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)"