之前学习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 的可变方法,用于计算原始值的平方值:

  1. extension Int {
  2. mutating func square() {
  3. self = self * self
  4. }
  5. }

下标(Subscripts)

扩展可以为已有类型添加新下标。这个例子为 Swift 内建类型 Int 添加了一个整型下标。该下标 [n] 返回十进制数字从右向左数的第 n 个数字:

123456789[0] 返回 9

123456789[1] 返回 8

嵌套类型(Nested Types)

扩展可以为已有的类、结构体和枚举添加新的嵌套类型:

协议

Mutating 方法要求

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

将 mutating 关键字作为方法的前缀,写在 func 关键字之前,表示可以在该方法中修改它所属的实例以及实例的任意属性的值

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

协议构造器要求

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

  1. protocol SomeProtocol {
  2. init(someParameter: Int)
  3. }

构造器要求在类中的实现

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

  1. class SomeClass: SomeProtocol {
  2. required init(someParameter: Int) {
  3. // 这里是构造器的实现部分
  4. }
  5. }

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

构造器要求

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

protocol SomeProtocol {

init(someParameter: Int)

}

构造器要求在类中的实现

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

  1. class SomeClass: SomeProtocol {
  2. required init(someParameter: Int) {
  3. // 这里是构造器的实现部分
  4. }
  5. }

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

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

  1. protocol SomeProtocol {
  2. init()
  3. }
  4. class SomeSuperClass {
  5. init() {
  6. // 这里是构造器的实现部分
  7. }
  8. }
  9. class SomeSubClass: SomeSuperClass, SomeProtocol {
  10. // 因为采纳协议,需要加上 required
  11. // 因为继承自父类,需要加上 override
  12. required override init() {
  13. // 这里是构造器的实现部分
  14. }
  15. }

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

协议作为类型

尽管协议本身并未实现任何功能,但是协议可以被当做一个成熟的类型来使用。

  • 作为函数、方法或构造器中的参数类型或返回值类型
  • 作为常量、变量或属性的类型
  • 作为数组、字典或其他容器中的元素类型

通过扩展采纳协议

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

  1. struct Hamster {
  2. var name: String
  3. var textualDescription: String {
  4. return "A hamster named \(name)"
  5. }
  6. }
  7. extension Hamster: TextRepresentable {}

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

  1. let simonTheHamster = Hamster(name: "Simon")
  2. let v1: TextRepresentable = simonTheHamster // 可以赋值
  3. print(v1.textualDescription)

即使满足了协议的所有要求,类型也不会自动采纳协议,必须显式地采纳协议。

协议类型的集合

协议类型可以在数组或者字典这样的集合中使用,在协议类型提到了这样的用法。下面的例子创建了一个元素类型为 TextRepresentable 的数组:

let things: [TextRepresentable] = [game, d12, simonTheHamster]

如下所示,可以遍历 things 数组,并打印每个元素的文本表示:

  1. for thing in things {
  2. print(thing.textualDescription)
  3. }
  4. // A game of Snakes and Ladders with 25 squares
  5. // A 12-sided dice
  6. // A hamster named Simon

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

协议的继承

协议能够继承一个或多个其他协议,可以在继承的协议的基础上增加新的要求。协议的继承语法与类的继承相似,多个被继承的协议间用逗号分隔:

  1. protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
  2. // 这里是协议的定义部分
  3. }

类类型专属协议

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

  1. protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
  2. // 这里是类类型专属协议的定义部分
  3. }

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

协议合成

有时候需要同时采纳多个协议,你可以将多个协议采用 protocol<SomeProtocol, AnotherProtocol> 这样的格式进行组合,称为 协议合成(protocol composition)。你可以在 <> 中罗列任意多个你想要采纳的协议,以逗号分隔。

下面的例子中,将 Named 和 Aged 两个协议按照上述语法组合成一个协议,作为函数参数的类型:

  1. protocol Named {
  2. var name: String { get }
  3. }
  4. protocol Aged {
  5. var age: Int { get }
  6. }
  7. struct Person: Named, Aged {
  8. var name: String
  9. var age: Int
  10. }
  11. func wishHappyBirthday(celebrator: protocol<Named, Aged>) {
  12. print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
  13. }

协议合成并不会生成新的、永久的协议类型,而是将多个协议中的要求合成到一个只在局部作用域有效的临时协议中。

可选的协议要求

协议可以定义可选要求,采纳协议的类型可以选择是否实现这些要求。在协议中使用 optional 关键字作为前缀来定义可选要求。使用可选要求时(例如,可选的方法或者属性),它们的类型会自动变成可选的。比如,一个类型为 (Int) -> String 的方法会变成 ((Int) -> String)?。需要注意的是整个函数类型是可选的,而不是函数的返回值。

swift学习笔记4——扩展、协议的更多相关文章

  1. swift学习笔记之-扩展(Extensions)

    //扩展(Extensions) import UIKit /*扩展(Extensions):扩展 就是为一个已有的类.结构体.枚举类型或者协议类型添加新功能.这包括在没有权限获取原始源代码的情况下扩 ...

  2. Swift 学习笔记(扩展和泛型)

    在开始介绍Swift中的扩展之前,我们先来回忆一下OC中的扩展. 在OC中如果我们想对一个类进行功能的扩充,我们会怎么做呢. 对于面向对象编程的话,首先会想到继承,但是继承有两个问题. 第一个问题:继 ...

  3. 【swift学习笔记】二.页面转跳数据回传

    上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...

  4. Swift学习笔记(一)搭配环境以及代码运行成功

    原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...

  5. swift学习笔记之-协议

    //协议(Protocols) import UIKit /*协议(Protocols) 1.协议定义了一个蓝图,规定了用来实现某一特定任务或者功能的方法.属性,以及其他需要的东西 2.类.结构体或枚 ...

  6. Swift 学习笔记(面向协议编程)

    在Swift中协议不仅可以定义方法和属性,而且协议是可以扩展的,最关键的是,在协议的扩展中可以添加一些方法的默认实现,就是在协议的方法中可以实现一些逻辑,由于这个特性,Swift是可以面向协议进行编程 ...

  7. swift学习笔记5——其它部分(自动引用计数、错误处理、泛型...)

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  8. swift学习笔记1——基础部分

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  9. 记录:swift学习笔记1-2

    swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...

随机推荐

  1. .NET Portability Analyzer 已开源

    在一年前介绍过<介绍.NET 开发必备工具 .NET Portability Analyzer>,微软已经把代码开源到Github:https://github.com/Microsoft ...

  2. Angular移除不必要的$watch之性能优化

    双向绑定是Angular的核心概念之一,它给我们带来了思维方式的转变:不再是DOM驱动,而是以Model为核心,在View中写上声明式标签.然后,Angular就会在后台默默的同步View的变化到Mo ...

  3. 将WordPress安装在网站子目录的相关问题

    May182013 将WordPress安装在网站子目录的相关问题 作者:xieyc   发布:2013-05-18 00:11   字符数:3423   分类:站长   阅读: 12,054 次   ...

  4. webpack入门之简单例子跑起来

    webpack介绍 Webpack是当下最热门的前端资源模块化管理和打包工具,它可以将很多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源,还可以将按需加载的模块进行代码分割,等到实际需要的时 ...

  5. CentOS7安装iptables防火墙

    CentOS7默认的防火墙不是iptables,而是firewalle. 安装iptable iptable-service #先检查是否安装了iptables service iptables st ...

  6. 数据结构:二叉查找树(C语言实现)

    数据结构:二叉查找树(C语言实现) ►写在前面 关于二叉树的基础知识,请看我的一篇博客:二叉树的链式存储 说明: 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: 1.若其左子树不空,则左子树上 ...

  7. 面向对象的JS(一)

    JavaScript是弱类型,可变性强 /*JavaScript和其他的语言类似,也是面向对象,自然也就是存在类和对象(对象是类的实例化)*/ //1.JS对象 var empty = {}; //没 ...

  8. [摘录]第三部分 IBM文化(2)

    第二十二章 原则性领导 在一个组织程序已经变得不受其来源和内容的约束,而且其编纂出来的组织宗旨已经代替了个人责任的组织之中,你所面临的首要任务,就是要全盘抹掉这个程序本身,以便让整个封闭的系统呼吸新鲜 ...

  9. NLP&数据挖掘基础知识

    Basis(基础): SSE(Sum of Squared Error, 平方误差和) SAE(Sum of Absolute Error, 绝对误差和) SRE(Sum of Relative Er ...

  10. Android面试经验 -- 乐视

    此次投的是三年经验的Android开发,最后反而因为自己的失误,没有准备充分而导致结果很悲剧,以此告诫自己千万不能疏忽大意. 面试过程 第一次去大公司面试,心里不是一般的激动和紧张,来到乐视大厦门口, ...