swift 学习- 25 -- 协议 02

// 通过扩展添加协议一致性

// 即便无法修改源代码, 依然可以通过扩展 令已有类型遵循并符合协议, 扩展可以为已有类型添加属性, 方法, 下标 以及构造器, 因此可以符合协议中的相应要求

// 注意: 通过扩展令已有类型遵循并符合协议时, 该类型的所有势力也会随之获得协议中定义的各项功能

protocol TextRepresentbble{

var textualDescription: String { get }

}

// 可以通过扩展, 令已有的类 Dice 遵循并符合 TextRepresentable 协议:

// extension Dice: TextOutputStream{

//     var textualDescription: String{

//         return "ddddd"

//     }

// }

// 通过扩展遵循并符合协议, 和在原始定义中遵循并符合协议的效果完全相同, 协议名称写在类型名之后, 以冒号隔开, 然后在扩展的大括号内实现协议要求的内容

// 通过扩展遵循协议

// 当一个类型已经符合某个协议中的所有要求, 却还没有声明遵循该协议时, 可以通过空扩展体来遵循该协议:

struct Hamster{

var name: String

var textualDescription: String {

return "A hamster named \(name)"

}

}

extension Hamster: TextRepresentbble{}

// 从现在起, Hamster 的实例可以作为 TextRepresentable 类型使用

let simonTheHamster = Hamster.init(name: "Simon")

let somethingTextRepresentable: TextRepresentbble = simonTheHamster

print(somethingTextRepresentable.textualDescription)

// 注意: 即使满足了协议的所有要求, 类型也不会自动遵循协议, 必须显式地遵循协议

// 协议类型的集合

// 协议类型可以在数组或字典这样的集合中使用

let things: [TextRepresentbble] = [simonTheHamster]

// 如下所示, 可以便利 things 数组, 并打印每个元素的文本信息

for thing in things {

print(thing.textualDescription)

}

// thing 是 TextRepresentbble 类型而不是 Hamster 类型, 即使实例在幕后确实是这些类型中的一种, 由于 thing 是 TextRepresentbble 类型, 任何 TextRepresentbble 的实例都有一个 textualDescription 属性, 所以每次循环中可以安全地反问 thing.textualDescription

// 协议的继承

// 协议能够继承 一个 或 多个其他协议, 可以在继承 的协议的基础上增加新的要求, 协议的继承语法与 类的继承很相似, 多个被继承的协议之间用 (,) 分割

// protocol InheritingProtocol: SomeProtocol, AnotherProtocl{

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

// }

// 如下例所示:

protocol PrettyTextRepresentable: TextRepresentbble{

var prettyTextualDescription: String { get }

}

// 例子中定义了一个新的协议 PrettyTextRepresentable, 它继承自 TextRepresentable 协议, 任何遵循 PrettyTextRepresentable 洗衣的类型在满足该协议的要求时, 也必须满足 TextRepresentbble 协议的要求.

//extension SnakesAndLadders: PrettyTextRepresentable {

//    var prettyTextualDescription: String {

//        var output = textualDescription + ":\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

//    }

//}

//上述扩展令 SnakesAndLadders 遵循了 PrettyTextRepresentable 协议,并提供了协议要求的 prettyTextualDescription 属性。每个 PrettyTextRepresentable 类型同时也是 TextRepresentable 类型,所以在 prettyTextualDescription 的实现中,可以访问 textualDescription 属性。

// 类类型专属协议

// 你可以在协议的继承列表中, 通过添加 class 关键字来限制协议只能被 类类型遵循, 而结构体 或枚举不能遵循该协议, class 关键字必须第一个出现在协议的继承列表中, 在其他继承的协议之前:

// protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {

// 这里是类类型专属协议的定义部分

// }

// 在以上例子中,协议 SomeClassOnlyProtocol 只能被类类型遵循, 如果尝试让结构体或枚举 类型遵循该协议,则会导致编译错误

// 注意: 当协议定义的要求 需要遵循协议的 类型必须是 引用语义 而非 值语义, 应该采用类类型专属协议

// 协议合成

// 有时候需要同时遵循多个协议, 你可以将多个协议采用 SomeProtocol & AntherProtocol 这样的格式进行组合, 称为 协议合成. 你可以罗列任意多个你想要遵循的协议, 以与符号 (&) 分割

protocol Named{

var name: String{ get }

}

protocol Aged{

var age: Int { get }

}

struct Person: Named,Aged{

var name: String

var age: Int

}

func wishHappyBirthday(to celebrator: Named & Aged){

print("Happy birthday , \(celebrator.name), you‘re \(celebrator.age)")

}

let birthdayPerson = Person.init(name: "Malcolm", age: 21)

wishHappyBirthday(to: birthdayPerson)

// Named 协议包含 String 类型的 name 属性, Aged 协议包含 Int 类型的 age 属性, person 结构体遵循了这两个协议

// wishHappyBirthday(to:) 函数的参数 celebrator 的类型为 Named & Aged, 这意味着它不关心参数的具体类型, 只要参数符合这两个协议即可

// 注意: 协议合成不会生成新的, 永久的协议, 而是将多个协议中要求合成到一个只在局部作用域中有效的临时协议中

// 检查协议的一致性

// 你可以使用 类型转化 中 描述的 is 和 as 操作符来检查协议的一致性, 即是否符合某协议,并且可以指定转换到指定的协议类型, 检查很转化到某个协议类型在语法上和类型的检查和转换完全相同:

// is 用来检查视力是否符合某个协议, 若是返回 true, 否则返回 false

// 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

}

}

// Circle 类把 area 属性实现为基于存储型属性 radius 的计算型属性, Country 类则把 area 属性实现为存储型属性, 这两个类都正确地符合了 HasArea 协议

// 下面是一个未遵循 HasArea 协议的类

class Animal{

var legs: Int

init(legs: Int) {

self.legs = legs

}

}

// Circle. Country ,Animal 并没有一个共同的基类, 尽管如此, 他们都是类, 他们的实例都可以作为 AnyObject 类型的值, 存储在同一个数组中:

let objects: [AnyObject] = [

Circle.init(radius: 2.0),

Country.init(area: 243_610),

Animal.init(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")

}

}

// 当迭代出的元素符合 HasArea 协议时, 将 as? 操作符返回的可选值通过可选绑定, 绑定到 objectWithArea 常量上, objectWithAera 是 HasArea 协议类型的实例, 因此 area 属性可以被访问和打印

// objects 数组中的元素的类型并不会因为强转而丢失类型信息, 他们仍然是 Circle , Country , Animal 类型, 然而,当他们被赋值给 objectWithArea 常量时, 只被视为 HasArea 类型, 因此只有 area 属性能被访问

// 可选的协议要求

// 协议可以定义 可选要求. 遵循协议的类型可以选择是否实现这些要求, 在协议中使用 optional 关键字作为前缀 来定义可选要求, 可选要求用在你需要和 OC 打交道的代码中, 协议和可选要求都必须带上 @objc 属性, 标记 @objc 特性的协议只能被继承自 OC 类的类 或者 @objc 类遵循, 其他类以及结构体和 枚举不能遵循这种协议

// 使用可选要求时(例如, 可选的方法或者属性) , 他们的类型会自动变成可选的, 比如, 一个类型为 (Int) -> String 的方法会变成 ((Int) -> String)?, 需要注意的是整个函数类型是可选的, 而不是返回值是可选的

// 协议中的可选要求可通过可选链式调用来使用, 因为遵循协议的类型可能没有实现这些可选要求, 类似 someOptionalMethod?(someArgument) 这样,你可以在可选方法名称后加上 ? 来调用可选方法。

@objc protocol CounterDataSource{

@objc optional func incrementForCount(count: Int) -> Int

@objc optional var fixedIncrement: Int { get }

}

// 注意: 严格来讲, CounterDataSource 协议中的方法和属性都是可选的, 因此遵循协议的类可以不实现这些要求, 尽管技术上允许这么做, 不过做好不要这么写

class Counter{

var count = 0

var dataSource: CounterDataSource?

func increment() {

if let amount = dataSource?.incrementForCount?(count: count) {

count += amount

}else if let amount = dataSource?.fixedIncrement{

count += amount

}

}

}

// 协议扩展

// 协议可以通过扩展来为遵循协议的类型提供属性, 方法以及下标的实现, 你可以基于协议本身来实现这些功能, 而无需在每个遵循协议的类型中都重复同样的实现, 也无需使用全局函数

// 例如.

//extension SomeProtocol {

//    func randomBool() -> Bool {

//        return random() > 0.5

//    }

//}

// 通过协议扩展, 所有遵循协议的类型, 都能自动获得这个扩展所增加的方法实现, 无需任何额外的修改

// 提供默认实现

// 可以通过协议扩展来为协议要求的属性, 方法以及下标 提供默认的实现, 如果遵循协议的类型为这些要求提供了自己的实现, 那么这些自定义实现将会替代扩展中的默认实现被使用

// 注意: 通过协议扩展为协议要求提供的默认实现和可选的协议要求不同, 虽然在这两种情况下, 遵循协议的类都无需自己实现这些要求, 但是通过扩展提供的默认实现可以直接调用, 而无需使用可选链式调用

extension PrettyTextRepresentable{

var prettyTextualDescription: String {

return textualDescription

}

}

// 为扩展协议添加限制条件

// 在扩展协议的时候, 可以指定一些限制条件, 只有遵循协议的类型满足这些限制条件时. 才能获得协议扩展提供的默认实现, 协议限制条件写在协议名之后, 使用 whrer 子句来描述,

// 例如,你可以扩展 CollectionType 协议,但是只适用于集合中的元素遵循了 TextRepresentable 协议的情况:

// extension CollectionType where Generator.Element: TextRepresentbble{

//     // 扩展协议定义的内容

// }

时间: 2024-10-08 08:43:06

swift 学习- 25 -- 协议 02的相关文章

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 学习- 24 -- 协议 01

// 协议 定义了一个蓝图, 规定了用来实现某一特定任务或者功能的方法, 属性, 以及其他需要的东西. // 类, 结构体, 或 枚举都可以遵循协议, 并且为协议定义的这些要求 提供具体的实现, 某个类型能够满足某个协议的要求, 就可以说该类型 遵循了这个协议 // 除了遵循协议的类型必须实现的要求外, 还可以对协议进行扩展, 通过扩展来实现一部分或者实现一些附加功能, 这样遵循的协议的类型能够使用这些功能 // 协议的语法 // 协议的定义方式 与 类, 结构体 和 枚举的定义非常相似 //

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

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

SWIFT学习笔记02

1.//下面的这些浮点字面量都等于十进制的12.1875: let decimalDouble = 12.1875 let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0//==12+3*(1/16) 2.//类型别名,用typealias关键字来定义类型别名 typealias AudioSample = UInt16 var maxAmplitudeFound = AudioSample.min 3.//元组 let ht

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

Swift学习笔记(11)--类与结构体

类与结构是编程人员在代码中会经常用到的代码块.在类与结构中可以像定义常量,变量和函数一样,定义相关的属性和方法以此来实现各种功能. 和其它的编程语言不太相同的是,Swift不需要单独创建接口或者实现文件来使用类或者结构.Swift中的类或者结构可以在单文件中直接定义,一旦定义完成后,就能够被直接其它代码使用. 注意:一个类的实例一般被视作一个对象,但是在Swift中,类与结构更像是一个函数方法,在后续的章节中更多地是讲述类和结构的功能性. 1.类和结构的异同 类和结构有一些相似的地方,它们都可以

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学习笔记(一):基础

一.常量 & 变量 //常量 let constantsTeam = 1 //变量 var variablesTeam = 2 尽可能使用常量,这样更清晰并且内存更不容易肾亏. 二.显示/隐式指定类型 //隐式 let inferredTeam = 3 //显式 let explicitTeam:Int = 4 三.字符串输出 //通过\(变量或常量名)来引用组合字符串 println("\(inferredTeam) is bigger than \(variablesTeam)!&q