swift学习笔记4——扩展、协议
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习、总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询用。详细可以参考the-swift-programming-language-in-chinese,或者苹果官方英文版文档
当前版本是swift2.2
扩展(Extensions)
扩展 就是为一个已有的类、结构体、枚举类型或者协议类型添加新功能。这包括在没有权限获取原始源代码的情况下扩展类型的能力(即 逆向建模 )。扩展和 Objective-C 中的分类类似。(与 Objective-C 不同的是,Swift 的扩展没有名字。)
如果你通过扩展为一个已有类型添加新功能,那么新功能对该类型的所有已有实例都是可用的,即使它们是在这个扩展定义之前创建的。
计算型属性(Computed Properties)
扩展可以为已有类型添加计算型实例属性和计算型类型属性。不可以添加存储性属性
构造器(Initializers)
扩展可以为已有类型添加新的构造器。这可以让你扩展其它类型,将你自己的定制类型作为其构造器参数,或者提供该类型的原始实现中未提供的额外初始化选项。
扩展能为类添加新的便利构造器,但是它们不能为类添加新的指定构造器或析构器。指定构造器和析构器必须总是由原始的类实现来提供。
方法(Methods)
扩展可以为已有类型添加新的实例方法和类型方法。
可变实例方法(Mutating Instance Methods)
通过扩展添加的实例方法也可以修改该实例本身。结构体和枚举类型中修改 self 或其属性的方法必须将该实例方法标注为 mutating,正如来自原始实现的可变方法一样。
下面的例子为 Swift 的 Int 类型添加了一个名为 square 的可变方法,用于计算原始值的平方值:
extension Int {
mutating func square() {
self = self * self
}
}
下标(Subscripts)
扩展可以为已有类型添加新下标。这个例子为 Swift 内建类型 Int 添加了一个整型下标。该下标 [n] 返回十进制数字从右向左数的第 n 个数字:
123456789[0] 返回 9
123456789[1] 返回 8
嵌套类型(Nested Types)
扩展可以为已有的类、结构体和枚举添加新的嵌套类型:
协议
Mutating 方法要求
如果你在协议中定义了一个实例方法,该方法会改变采纳该协议的类型的实例,那么在定义协议时需要在方法前加 mutating 关键字。这使得结构体和枚举能够采纳此协议并满足此方法要求。
将 mutating 关键字作为方法的前缀,写在 func 关键字之前,表示可以在该方法中修改它所属的实例以及实例的任意属性的值
实现协议中的 mutating 方法时,若是类类型,则不用写 mutating 关键字。而对于结构体和枚举,则必须写 mutating 关键字。
协议构造器要求
协议可以要求采纳协议的类型实现指定的构造器。你可以像编写普通构造器那样,在协议的定义里写下构造器的声明,但不需要写花括号和构造器的实体:
protocol SomeProtocol {
init(someParameter: Int)
}
构造器要求在类中的实现
你可以在采纳协议的类中实现构造器,无论是作为指定构造器,还是作为便利构造器。无论哪种情况,你都必须为构造器实现标上 required 修饰符:
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// 这里是构造器的实现部分
}
}
使用 required 修饰符可以确保所有子类也必须提供此构造器实现,从而也能符合协议。
构造器要求
协议可以要求采纳协议的类型实现指定的构造器。你可以像编写普通构造器那样,在协议的定义里写下构造器的声明,但不需要写花括号和构造器的实体:
protocol SomeProtocol {
init(someParameter: Int)
}
构造器要求在类中的实现
你可以在采纳协议的类中实现构造器,无论是作为指定构造器,还是作为便利构造器。无论哪种情况,你都必须为构造器实现标上 required 修饰符:
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// 这里是构造器的实现部分
}
}
使用 required 修饰符可以确保所有子类也必须提供此构造器实现,从而也能符合协议。
如果一个子类重写了父类的指定构造器,并且该构造器满足了某个协议的要求,那么该构造器的实现需要同时标注 required 和 override 修饰符:
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// 这里是构造器的实现部分
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// 因为采纳协议,需要加上 required
// 因为继承自父类,需要加上 override
required override init() {
// 这里是构造器的实现部分
}
}
如果类已经被标记为 final,那么不需要在协议构造器的实现中使用 required 修饰符,因为 final 类不能有子类
协议作为类型
尽管协议本身并未实现任何功能,但是协议可以被当做一个成熟的类型来使用。
- 作为函数、方法或构造器中的参数类型或返回值类型
- 作为常量、变量或属性的类型
- 作为数组、字典或其他容器中的元素类型
通过扩展采纳协议
当一个类型已经符合了某个协议中的所有要求,却还没有声明采纳该协议时,可以通过空扩展体的扩展来采纳该协议:
struct Hamster {
var name: String
var textualDescription: String {
return "A hamster named \(name)"
}
}
extension Hamster: TextRepresentable {}
从现在起,Hamster 的实例可以作为 TextRepresentable 类型使用:
let simonTheHamster = Hamster(name: "Simon")
let v1: TextRepresentable = simonTheHamster // 可以赋值
print(v1.textualDescription)
即使满足了协议的所有要求,类型也不会自动采纳协议,必须显式地采纳协议。
协议类型的集合
协议类型可以在数组或者字典这样的集合中使用,在协议类型提到了这样的用法。下面的例子创建了一个元素类型为 TextRepresentable 的数组:
let things: [TextRepresentable] = [game, d12, simonTheHamster]
如下所示,可以遍历 things 数组,并打印每个元素的文本表示:
for thing in things {
print(thing.textualDescription)
}
// A game of Snakes and Ladders with 25 squares
// A 12-sided dice
// A hamster named Simon
thing 是 TextRepresentable 类型而不是 Dice,DiceGame,Hamster 等类型,即使实例在幕后确实是这些类型中的一种。由于 thing 是 TextRepresentable 类型,任何 TextRepresentable 的实例都有一个 textualDescription 属性,所以在每次循环中可以安全地访问 thing.textualDescription。
协议的继承
协议能够继承一个或多个其他协议,可以在继承的协议的基础上增加新的要求。协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔:
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
// 这里是协议的定义部分
}
类类型专属协议
你可以在协议的继承列表中,通过添加 class 关键字来限制协议只能被类类型采纳,而结构体或枚举不能采纳该协议。class 关键字必须第一个出现在协议的继承列表中,在其他继承的协议之前:
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// 这里是类类型专属协议的定义部分
}
在以上例子中,协议 SomeClassOnlyProtocol 只能被类类型采纳。如果尝试让结构体或枚举类型采纳该协议,则会导致编译错误。
协议合成
有时候需要同时采纳多个协议,你可以将多个协议采用 protocol<SomeProtocol, AnotherProtocol> 这样的格式进行组合,称为 协议合成(protocol composition)。你可以在 <> 中罗列任意多个你想要采纳的协议,以逗号分隔。
下面的例子中,将 Named 和 Aged 两个协议按照上述语法组合成一个协议,作为函数参数的类型:
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>) {
print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
}
协议合成并不会生成新的、永久的协议类型,而是将多个协议中的要求合成到一个只在局部作用域有效的临时协议中。
可选的协议要求
协议可以定义可选要求,采纳协议的类型可以选择是否实现这些要求。在协议中使用 optional 关键字作为前缀来定义可选要求。使用可选要求时(例如,可选的方法或者属性),它们的类型会自动变成可选的。比如,一个类型为 (Int) -> String 的方法会变成 ((Int) -> String)?。需要注意的是整个函数类型是可选的,而不是函数的返回值。
swift学习笔记4——扩展、协议的更多相关文章
- swift学习笔记之-扩展(Extensions)
//扩展(Extensions) import UIKit /*扩展(Extensions):扩展 就是为一个已有的类.结构体.枚举类型或者协议类型添加新功能.这包括在没有权限获取原始源代码的情况下扩 ...
- Swift 学习笔记(扩展和泛型)
在开始介绍Swift中的扩展之前,我们先来回忆一下OC中的扩展. 在OC中如果我们想对一个类进行功能的扩充,我们会怎么做呢. 对于面向对象编程的话,首先会想到继承,但是继承有两个问题. 第一个问题:继 ...
- 【swift学习笔记】二.页面转跳数据回传
上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...
- Swift学习笔记(一)搭配环境以及代码运行成功
原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...
- swift学习笔记之-协议
//协议(Protocols) import UIKit /*协议(Protocols) 1.协议定义了一个蓝图,规定了用来实现某一特定任务或者功能的方法.属性,以及其他需要的东西 2.类.结构体或枚 ...
- Swift 学习笔记(面向协议编程)
在Swift中协议不仅可以定义方法和属性,而且协议是可以扩展的,最关键的是,在协议的扩展中可以添加一些方法的默认实现,就是在协议的方法中可以实现一些逻辑,由于这个特性,Swift是可以面向协议进行编程 ...
- swift学习笔记5——其它部分(自动引用计数、错误处理、泛型...)
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记1——基础部分
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- 记录:swift学习笔记1-2
swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...
随机推荐
- 【Java并发编程实战】-----“J.U.C”:CountDownlatch
上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一 ...
- NLog在Asp.Net MVC的实战应用
Asp.Net MVC FilterAttribute特性.读取xml反序列化.NLog实战系列文章 首先新建一个MVC project. 一.NLog的配置. 作者:Jarosław Kowalsk ...
- iOS-----程序异常处理----- 断言NSAssert()和NSParameterAssert区别和用处
NSAssert和assert是断言,主要的差别是assert在断言失败的时候只是简单的终止程序,而NSAssert会报告出错误信息并且打印出来.所以尽管的使用NSAssert,可以不去使用asser ...
- C#,.Net 学习资源
原文:http://blog.csdn.net/chinacsharper/article/details/17514923一.网站1.http://msdn.microsoft.com/zh-CN/ ...
- Java–cvc-complex-type.4:Attribut ‘version’ must appear on element ‘web-app’
问题解析: 在web.xml中的以下代码中 <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi=" ...
- QunInfo群数据库的还原与优化
一. 背景 这个数据库的数据文件mdf大概有8.5G左右,当还原数据库之后感觉可以做很多性能方面上的调优,合并数据后mdf数据文件大概有6.2G左右,行压缩后mdf数据文件大概有4.8G左右,页压缩后 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(21)-权限管理系统-跑通整个系统
系列目录 这一节我们来跑通整个系统,验证的流程,通过AOP切入方式,在访问方法之前,执行一个验证机制来判断是否有操作权限(如:增删改等) 原理:通过MVC自带筛选器,在筛选器分解路由的Action和c ...
- windows 环境下nginx + tomcat群 + redis 实现session共享
nginx作为负载均衡根据定义将不同的用户请求分发到不同的服务器,同时也解决了因单点部署服务器故障导致的整个应用不能访问的问题 在加入nginx之后,如果多个服务器中的一个或多个(不是全部)发生故障, ...
- java中的文件读取和文件写出:如何从一个文件中获取内容以及如何向一个文件中写入内容
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.Fi ...
- Vertica 导出数据测试用例
需求:构建简单的测试用例,完成演示Vertica导出数据的功能. 测试用例:导出test业务用户t_jingyu表中的数据. 一.初始化测试环境 二.导出数据 2.1 vsql命令说明帮助 2.2 导 ...