Swift学习:2.21 协议
参考Swift 官方教程《The Swift Programming Language》中文版
协议
协议的语法
protocol SomeProtocol {
// 协议内容
}
在类型名称后加上 struct SomeStructure: FirstProtocol,AnotherProtocol {
// 结构体内容
}
如果一个类在含有 class SomeClass: SomeSuperClass,FirstProtocol,AnotherProtocol {
// 类的内容
}
对属性的规定协议可以规定其 如果协议要求属性是可读写的,那么这个属性不能是常量 协议中的属性经常被加以 protocol SomeProtocol {
var mustBeSettable : Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
如下所示,通常在协议的定义中使用 protocol AnotherProtocol {
class 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")
// ncc1701.fullName == "USS Enterprise"
对方法的规定
如下所示,协议中类方法的定义与类属性的定义相似,在协议定义的方法前置 protocol SomeProtocol {
class func someTypeMethod() }
如下所示,定义了含有一个实例方法的的协议。 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()
println("Here's a random number: (generator.random())")
// 输出 : "Here's a random number: 0.37464991998171"
println("And another one: (generator.random())")
// 输出 : "And another one: 0.729023776863283"
对突变方法的规定有时不得不在方法中更改实例的所属类型。在基于 如果协议中的实例方法打算改变其
如下所示, 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 SomeProtocol {
init(someParameter: Int)
}
协议构造器规定在类中的实现 你可以在遵循该协议的类中实现构造器,并指定其为类的特定构造器或者便捷构造器。在这两种情况下,你都必须给构造器实现标上"required"修饰符: class SomeClass: SomeProtocol {
required init(someParameter: Int) {
//构造器实现
}
}
使用 关于
如果一个子类重写了父类的指定构造器,并且该构造器遵循了某个协议的规定,那么该构造器的实现需要被同时标示 protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
//协议定义
}
}
class SomeSubClass: SomeSuperClass,SomeProtocol {
// "required" from SomeProtocol conformance; "override" from SomeSuperClass
required override init() {
// 构造器实现
}
}
可失败构造器的规定 可以通过给协议 如果在协议中定义一个可失败构造器,则在遵顼该协议的类型中必须添加同名同参数的可失败构造器或非可失败构造器。 如果在协议中定义一个非可失败构造器,则在遵循该协议的类型中必须添加同名同参数的非可失败构造器或隐式解析类型的可失败构造器( 协议类型尽管 使用场景:
如下所示,这个示例中将协议当做类型来使用 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 {
println("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
委托(代理)模式委托是一种设计模式(译者注: 想起了那年 UITableViewDelegate 中的奔跑,那是我逝去的Objective-C。。。),它允许 委托模式的实现很简单: 定义 委托模式可以用来响应特定的动作或接收外部数据源提供的数据,而无需要知道外部数据源的所属类型(译者注:只要求外部数据源 下文是两个基于骰子游戏的协议: 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 {
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
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
在扩展中添加协议成员即便无法修改源代码,依然可以通过
protocol TextRepresentable {
func asText() -> String }
通过 extension Dice: TextRepresentable {
func asText() -> String {
return "A (sides)-sided dice"
}
}
从现在起, let d12 = Dice(sides: 12,generator: LinearCongruentialGenerator())
println(d12.asText())
// 输出 "A 12-sided dice"
extension SnakesAndLadders: TextRepresentable {
func asText() -> String {
return "A game of Snakes and Ladders with (finalSquare) squares"
}
}
println(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 {}
从现在起, let simonTheHamster = Hamster(name: "Simon")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
println(somethingTextRepresentable.asText())
// 输出 "A hamster named Simon"
集合中的协议类型协议类型可以被集合使用,表示集合中的元素均为协议类型: let things: [TextRepresentable] = [game,d12,simonTheHamster]
如下所示, for thing in things {
println(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
}
}
在
任意 println(game.asPrettyText())
// A game of Snakes and Ladders with 25 squares:
// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○
类专属协议你可以在协议的继承列表中,通过添加“class”关键字,限制协议只能适配到类(class)类型。(结构体或枚举不能遵循该协议)。该“class”关键字必须是第一个出现在协议的继承列表中,其后,才是其他继承协议。 protocol SomeClassOnlyProtocol: class,SomeInheritedProtocol {
// class-only protocol definition goes here
}
在以上例子中,协议SomeClassOnlyProtocol只能被类(class)类型适配。如果尝试让结构体或枚举类型适配该协议,则会出现编译错误。
协议合成一个协议可由多个协议采用 举个例子: protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named,Aged {
var name: String
var age: Int
}
func wishHappyBirthday(celebrator: protocol<Named,Aged>) {
println("Happy birthday (celebrator.name) - you're (celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm",age: 21)
wishHappyBirthday(birthdayPerson)
// 输出 "Happy birthday Malcolm - you're 21!
检验协议的一致性使用
@objc 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 }
}
如下所示,Animal是一个没有实现 class Animal {
var legs: Int
init(legs: Int) { self.legs = legs }
}
let objects: [AnyObject] = [
Circle(radius: 2.0),Country(area: 243_610),Animal(legs: 4)
]
如下所示, for object in objects {
if let objectWithArea = object as? HasArea {
println("Area is (objectWithArea.area)")
} else {
println("Something that doesn't have an area")
}
}
// Area is 12.5663708
// Area is 243610.0
// Something that doesn't have an area
当迭代出的元素遵循
对可选协议的规定可选协议含有可选成员,其 可选协议在调用时使用 像
如下所示, @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) {
count += amount
} else if let amount = dataSource?.fixedIncrement? {
count += amount
}
}
}
在调用 当
class ThreeSource: CounterDataSource { let fixedIncrement = 3 } 使用 var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
counter.increment()
println(counter.count)
}
// 3
// 6
// 9
// 12
class TowardsZeroSource: 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()
println(counter.count)
}
// -3
// -2
// -1
// 0
// 0 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |