swift 学习- 24 -- 协议 01

// 协议 定义了一个蓝图, 规定了用来实现某一特定任务或者功能的方法, 属性, 以及其他需要的东西.

// 类, 结构体, 或 枚举都可以遵循协议, 并且为协议定义的这些要求 提供具体的实现, 某个类型能够满足某个协议的要求, 就可以说该类型 遵循了这个协议

// 除了遵循协议的类型必须实现的要求外, 还可以对协议进行扩展, 通过扩展来实现一部分或者实现一些附加功能, 这样遵循的协议的类型能够使用这些功能

// 协议的语法

// 协议的定义方式 与 类, 结构体 和 枚举的定义非常相似

// protocol SomeProtocol{

//     // 这里是协议的定义部分

// }

//要让自定义类型遵循某个协议, 在定义类型时, 需要在类型名称后面 加上协议名称, 中间已 (:) 分割,遵循多个协议时, 各协议之间以 (,) 分割

// struct SomeStruct: FirstProtocol,AnotherProtocol{

//     // 这里是结构体的定义部分

// }

// 拥有父类的类在组训协议时, 应该将父类的类名放在协议名前面, 以 (,) 分割

// class SomeClass: SomeSuperClass.FirstProtocol,AnotherProtocol{

//     // 这里是类的定义部分

// }

// 属性要求

// 协议 可以要求遵循协议的类型 提供特定名称 和 类型的 实例属性 或类型属性

// 协议 不指定属性是存储型属性 还是 计算型属性, 它只指定属性的名称 和 类型, 此外,协议号指定属性是 可读还是 可读可写的

// 如果协议要求属性是可读可写的, 那么属性不能是常量属性 或只读的计算型属性, 如果协议要求属性是可读的,那么该属性不仅是可读的, 如果代码需要的话. 还可以是可写的

// 协议总是 用 var 关键字来声明变量属性, 在类型名称后面 加上 { set get} 来表示属性是可读可写的, 可读属性则用 {get} 来声明

protocol SomeProtocol{

var mustBeSettable: Int {get set}

var doseNotNeedToBeSettable: Int {get}

}

// 在协议中定义类型属性时, 总是使用 static 关键字作为前缀, 当类类型遵循协议时, 除了 static 关键字,还可以使用 class 关键字来声明类型属性:

protocol AnotherProtocol{

static var someTypeProperty: Int {get set}

}

// 如下所示: 这是一个只含有一个实例属性要求的协议:

protocol FullNamed{

var fullName: String {get}

}

// FullNamed 协议除了要求遵循协议的类型 提供的 fullName 属性外, 并没有其他要求, 这个协议表示, 任何遵循 FullNamed 的类型, 都必须有一个刻度的 String 类型的实例属性 fullName

// 下面是一个遵循 FullNamed 协议的简单结构体

struct Person: FullNamed{

var fullName: String

}

let john = Person.init(fullName: "John Appleseed")

// 这个例子定义了一个 Person 的结构体, 用来表示一个具有名字的人, 它遵循了 FullNamed 协议

// Person 结构体的每一个实例都有一个 String 类型的存储型属性, fullName, 这正好满足了 FullNamed 协议的要求, 就以为着 Person 结构体 正确地符合了协议 (如果协议要求未被完全满足, 在编译时会报错)

// 下面是一个更复杂的例子

class Starship: FullNamed{

var prefix: String?

var name: String

init(name: String,prefix: String?) {

self.name = name

self.prefix = prefix

}

var fullName: String{

return (prefix != nil ? prefix! + " ":"") + name

}

}

var ncc1701 = Starship.init(name: "Enterprise", prefix: "USS")

// 方法要求

// 协议可以要求 遵循协议的类型 实现某些指定的实例方法 或类方法, 这些方法作为协议的一部分,像普通方法一样放在协议的定义中, 但是不需要大括号和方法体, 可以在协议中定义具有可变参数的方法, 和普通方法一样, 但是, 不支持为协议中的方法的参数提供默认值

// 正如属性要求中所述, 在协议中定义类方法的时候, 总是使用 static 关键字作为前缀, 当类类型遵循雷伊的时候,除了 static 关键字外, 还可以使用 class 关键字作为前缀.

// 下面的例子定义了一个只含有一个实例方法的协议:

protocol RandomNumberGenerator{

func random() -> Double

}

// RandomNumberGenerator 协议要求遵循协议的类型必须拥有一个名为 random ,返回值类型为 Double 的实例方法.尽管这里并未指明,但是我们假设返回值在 [0.0,1.0] 区间内

// RandomNumberGenerator 协议并不关心每一个随机数是怎么生成的,它只要求必须提供一个随机数生活器

// 如下所示:

class LinearCongrentialGenerator: RandomNumberGenerator{

var lastRandom = 42.0

let m = 139968.0

let a = 3877.0

let c = 29573.0

func random() -> Double {

lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy: m))

return lastRandom / m

}

}

let  generator = LinearCongrentialGenerator.init()

print("Here‘s a random number : \(generator.random())")

print("And another one: \(generator.random())")

// Mutating 方法要求

// 有时需要在方法中改变方法所属的实例, 例如, 在值类型(即结构体和枚举)的实例方法中, 将 ,mutating 关键字作为方法的前缀, 写在 func 前面, 表示可以在该方法中修改它所属的实例以及实例的任意属性的值,

// 如果你在协议中定义了一个实例方法,该方法会改变遵循该协议的类型的实例, 那么在定义协议是需要在方法前加 ,mutating 关键字, 这使得结构体 和 枚举能够遵循协议并满足此方法要求

// 注意 : 实现协议中的 mutating 方法时, 若是类类型, 则不用写 mutating 关键字, 而对于结构体和枚举, 则必须写 mutataing 关键字

protocol Togglable{

mutating func toggle()

}

// toggle() 方法在定义的时候,使用 mutating 关键字标记,这表明当它被调用的时候, 该方法将会改变遵循协议的 类型的实例

// 当使用 枚举 或结构体 来实现 Togglable 协议的时候,需要提供一个带有 mutating 前缀的 toggle() 方法

enum OneOffSwitch: Togglable{

case off, on

mutating func toggle() {

switch self {

case .off:

self = .on

case .on:

self = .off

}

}

}

var lightSwitch = OneOffSwitch.off

lightSwitch.toggle()

// 构造器要求

// 协议可以要求遵循协议的类型实现指定的构造器, 你可以想编写普通构造器那样, 在协议的定义里写下构造器的声明, 但不需要写花括号和构造器的实体

protocol SomeProtocol2{

init(someParameter: Int)

}

// 构造器要求在类中的实现

// 你可以在遵循协议的类中实现构造器, 无论是作为制定构造器 ,还是作为便利构造器, 无论哪种情况,你都必须为构造器实现标上 required 修饰符

class SomeClass: SomeProtocol2{

required init(someParameter: Int) {

// 这里是构造器的实现部分

}

}

// 使用 required 修饰符可以确保所有子类必须 提供此构造器实现, 从而也能复合协议

// 如果类已经被标记为 final ,那么不需要再协议的构造器的实现值使用 required 修饰符,因为 final 类 不能有子类

// 如果一个子类重写了父类的指定构造器, 并且该构造器满足了某个协议的要求, 那么该构造器的实现需要同时标注 required 和 override 修饰符

protocol SomeProtocol3 {

init()

}

class SomeSuperClass3 {

init() {

// 这里是构造器的实现部分

}

}

class SomeSubClass: SomeSuperClass3, SomeProtocol3 {

// 因为遵循协议,需要加上 required

// 因为继承自父类,需要加上 override

required override init() {

// 这里是构造器的实现部分

}

}

// 可失败构造器要求

// 协议还可以为遵循协议的类型定义可失败的构造器要求

// 遵循协议的类型可以通过课时表的构造器 (init?) 或 非可失败的构造器 (init) 来满足协议中定义的可失败的构造器的要求

// 协议中定义的非可失败构造器要求可以通过非可失败构造器 (init) 或隐式解包可失败构造器 (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

}

}

// 委托 (代理) 模式

// 委托 是一种设计模式, 它允许类 或结构体将一些 需要他们负责的功能 委托给其他类型的实例, 委托模式的实现很简单: 定义协议来封装那些需要被委托的功能, 这样就能确保遵循协议的类型能提供这些功能, 委托模式可以用来响应特定的动作, 或者接受外部数据源的数据, 而无需关心外部数据源的类型

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)

}

// DiceGame 协议可以被任意涉及骰子的游戏遵循, DiceGameDelegate 协议可以被任意类型遵循, 用来追踪 DiceGame 的游戏过程

// 如下所示.

class SankesAndLadders: DiceGame{

let finalSquare = 25

let dice = Dice.init(sides: 6, generator: LinearCongrentialGenerator())

var square = 0

var board: [Int]

init() {

board = [Int].init(repeating: 0, count: finalSquare + 1)

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)

}

}

// 如下实例定义了 DiceGameTracker 类, 它遵循 DiceGameDelegate 协议:

class DIcegameTracker: DiceGameDelegate{

var numberOfTurns = 0

func gameDidStart(_ game: DiceGame) {

numberOfTurns = 0

if game is SankesAndLadders {

print("Started a new game of Snaks and Ladders")

}

print("The game is using a \(game.dice.sides)-sided dice")

}

func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {

numberOfTurns += 1

print("Rolled a \(diceRoll)")

}

func gameDidEnd(_ game: DiceGame) {

print("The game lasted for \(numberOfTurns) turns")

}

}

时间: 2024-10-11 14:55:34

swift 学习- 24 -- 协议 01的相关文章

Swift学习笔记-协议(Protocols)

  1.0 翻译:geek5nan 校对:dabing1022 2.0 翻译:futantan 校对:小铁匠Linus 定稿:shanksyang 本页包含内容: 协议的语法(Protocol Syntax) 对属性的规定(Property Requirements) 对方法的规定(Method Requirements) 对Mutating方法的规定(Mutating Method Requirements) 对构造器的规定(Initializer Requirements) 协议类型(Pro

swift 学习- 25 -- 协议 02

// 通过扩展添加协议一致性 // 即便无法修改源代码, 依然可以通过扩展 令已有类型遵循并符合协议, 扩展可以为已有类型添加属性, 方法, 下标 以及构造器, 因此可以符合协议中的相应要求 // 注意: 通过扩展令已有类型遵循并符合协议时, 该类型的所有势力也会随之获得协议中定义的各项功能 protocol TextRepresentbble{ var textualDescription: String { get } } // 可以通过扩展, 令已有的类 Dice 遵循并符合 TextRe

SWIFT学习笔记01

1.Swift,用来判断option是不是nil,相当于OC的 if(option) if let name = option{ greeting = "if=====" }else{ greeting = "else===" } 2.运行switch中匹配到的子句之后,程序会退出switch语句,并不会继续向下运行,所以不需要在每个子句结尾写break. 3.//使用..创建的范围不包含上界,如果想包含的话需要使用...,集合上,就是[)与[]的关系 for i

Swift学习第八枪--协议(二)

协议(二) 这篇紧接着前面的协议(一)继续总结. 1.委托(代理)模式 委托是一种设计模式,它允许 类 或 结构体 将一些需要它们负责的功能 交由(委托) 给其他的类型的实例.委托模式的实现很简单: 定义协议来封装那些需要被委托的函数和方法, 使其 遵循者 拥有这些被委托的 函数和方 法 .委托模式可以用来响应特定的动作或接收外部数据源提供的数据,而无需要知道外部数据源的类型信息. 下面的例子是两个基于骰子游戏的协议: protocol DiceGame { var dice: Dice { g

Swift学习——A Swift Tour 协议和扩展

Protocols and Extensions Protocols  协议的使用 使用关键字 protocol 定义一个协议 protocol ExampleProtocol { var simpleDescription: String { get } mutating func adjust() } 类,枚举和结构体都可以实现协议 class SimpleClass: ExampleProtocol { var simpleDescription: String = "A very sim

IOS开发语言Swift入门连载---协议

IOS开发语言Swift入门连载-协议 协议(Protocol) 协议(Protocol)用于定义完成某项任务或功能所必须的方法和属性,协议实际上并不提供这些功能或任务的具体实现(Implementation) –而只用来描述这些实现应该是什么样的.类,结构体,枚举通过提供协议所要求的方法,属性的具体实现来采用(adopt) 协议.任意能够满足协议要求的类型被称为协议的遵循者. 协议可以要求其遵循者提供特定的实例属性,实例方法,类方法,操作符或下标脚本等. 协议的语法 协议 的定义方式与类,结构

Swift学习——A Swift Tour 枚举和结构体

Enumerations and Structures Enumerations   枚举的使用 使用 enum 定义一个枚举,枚举里面可以关联方法,比如下文中的描述方法 enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { ca

Swift学习笔记(三):Protocols and Delegates

一.协议 | Protocols 协议用于定义完成某些功能所需要的方法和属性,协议本身并不提供这些功能的具体实现,只是用来描述这些实现.类.结构体.枚举通过提供协议所要求的方法.属性的具体实现来采用协议.能够满足协议要求的类型称之为协议的遵循者. 协议可以要求遵循者提供特定的实例属性.实例方法.类方法.操作符或下标脚本等. //创建一个协议,协议说声明了一个方法Speak protocol Speaker { func Speak() } //类Vicki遵循Speaker协议,在类中具体实现了

Swift学习第二练——Swift项目时光电影

Swift学习第二练--Swift项目时光电影 很早以前的一个OC的练习项目,用swift重新写了一遍,因为xcode版本的更新对swift的兼容度也在不断改变,此版本适用于xcode6.1. 这个项目中,用swift将iOS官方SDK中的HTTP进行了封装,使用了swift编写的异步加载网络图片的方法.练习了用swift操作界面布局,跳转界面等的方法. 下面是封装的下载类的核心代码: private var httpConnection:NSURLConnection? class ZYHHt