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 ...
随机推荐
- embedding mono实战笔录(一)
最近在给自己的服务器节点添加脚本功能,考虑到 执行性能.开发效率.调试效率.可维护性.严谨性 五大要素,最终选用C#作为脚本语言,并使用mono作为中间层,使其具备跨平台特性,以备具有在Windows ...
- 一步步学习javascript基础篇(9):ajax请求的回退
需求1: ajax异步请求 url标识请求参数(也就是说复制url在新页面打开也会是ajax后的效果) ajax异步请求没问题,问题一般出在刷新url后请求的数据没了,这就是因为url没有记录参数.如 ...
- 2000条你应知的WPF小姿势 基础篇<69-73 WPF Freeze机制和Template>
在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000ThingsYou Should Know About C# 和 2,00 ...
- SQL Server页类型汇总+疑问
该文章整理自:http://www.sqlnotes.info/2011/10/31/page-type/ SQL Server中包含多种不同类型的页,来满足数据存储的需求.不管是什么类型的页,它们的 ...
- APUE fig 1.10示例代码的完善--对提示符及输入回车的优化
APUE 第3版第15页的shell2.c示例程序,运行效果如下: gcc ol.shell.c -o origin_shell ./origin_shell % date 2015年12月13日 星 ...
- Java笔记——Java8特性之Lambda、方法引用和Streams
Java8已经推出了好一段时间了,而掌握Java8的新特性也是必要的,如果要进行Spring开发,那么可以发现Spring的官网已经全部使用Java8来编写示例代码了,所以,不学就看不懂. 这里涉及三 ...
- Cookie和Session的总结
1.开篇 在之前学习这一段的时候我一直有点没弄清楚,其实对Session这块的理解还可以,但是Cookie感觉始终还是欠缺点火候.之后的很长一段时间都基本上很少用Cookie了,渐渐的也淡忘了这一块的 ...
- WCF学习之旅—WCF服务的Windows 服务程序寄宿(十一)
上接 WCF学习之旅—WCF服务部署到IIS7.5(九) WCF学习之旅—WCF服务部署到应用程序(十) 七 WCF服务的Windows 服务程序寄宿 这种方式的服务寄宿,和IIS一样有一个一样 ...
- Git异常:fatal: could not create work tree dir 'XXX': No such file or directory
GitHub实战系列汇总:http://www.cnblogs.com/dunitian/p/5038719.html ———————————————————————————————————————— ...
- MSSQLSERVER执行计划详解
序言 本篇主要目的有二: 1.看懂t-sql的执行计划,明白执行计划中的一些常识. 2.能够分析执行计划,找到优化sql性能的思路或方案. 如果你对sql查询优化的理解或常识不是很深入,那么推荐几骗博 ...