创建: 2018/02/27

完成: 2018/02/28

更新: 2018/03/07 增加类采用协议时的注意

补充只有类, 结构体, 枚举型可以采用协议

增加为类定义准备的协议( protocol Sample: class, ... { ... } )

【任务表】TODO

协议(protocol)
 协议

区分于具体的实现, 集中进行类型应该有的方法和属性的声明的功能

● 应用某协议叫做采用协议

● 只有类, 结构体, 枚举型可以采用协议

 作为程序构成单位的协议

● 其他语言里叫协议(protocol)/接口(interface)/抽象类

● 协议, 扩张, 泛型紧密相关

 采用协议

采用协议的写法:

struct/class 类型名: 协议名 { // 多个协议用逗号隔开
...
}

public protocol CustomStringConvertiable { // 固有的协议, 采用的可以直接作为文字参数, 如放到print里
public var description: String { get }
} struct Sample: CustomStringConvertiable { // 采用上面协议的结构体
...
}

可被构造体, 类采用

协议的声明
 协议声明的概要
protocol 协议名: 继承的协议 { // 可以不继承
static func 方法(参数) -> 类型 // 实例方法,静态方法
static var 属性名: 类型 { get set } // 实例属性, 静态属性: set可省略
static 运算符种类 func 运算符(参数) -> 类型 // 运算符: 二项运算符不用写种类
init(参数)
subscript(参数) -> 类型 { get set } // 索引: set可省略
typealias 新型名 = 原型名
associatedtype 识别符号
}

● 顺序不限,数量不限

● 协议可以继承其他协议

协议里可以包含

● 实例方法, 静态方法

● 实例属性, 静态属性

● 运算符的函数声明

● 构造函数

● 索引(subscript)

● 附属型(typealias, associatedtype), 不能在协议里自己定义新的型

 类采用协议的注意 
 static 属性/方法

可以以静态或类属性/方法来实现

static/class

以静态属性/方法来实现

static

 mutating

参照型,

不需要mutating

改变自身

要加mutating

 构造函数

成为必须构造函数

required

● 带final的不需要required, 因为不会被继承

 构造函数来实现
   
 为类定义准备的协议 

● 只有类, 结构体, 枚举型可以采用协议

 ● 只运行类采用的协议定义方法

protocol 协议名: class, 继承的协议 { // 协议名后加上class
... // 方法不用也不能附mutating
}
 方法的声明与定义

● 改变自身的方法前面加mutating(类协议不需要)

● 只记声明,不写定义。可以在扩展里写定义作为默认的实现

 属性的声明与定义 

● 指定可读或者读写, get和set顺序不限, 只写声明

● 指定为可读的可以实现为读写

● 协议里都要写作var

● 计算型和容纳型都可以, 不限定

● 静态属性前面加static

 索引的声明与定义

和属性的声明与定义一样

 作为型的协议

func 方法名(参数1: [协议], ...) -> 类型 {
...
}

● 只能执行协议声明的操作

 协议的继承

protocol 协议: 继承的协议 {
...
}

● 逗号隔开

● 实现方法自由

● 不能有重名不同型的属性

 协议的合成

协议1 & 协议2 ... // 几个已有协议的和集合, 不添加任何新东西
//相当于
protocol newProtocol: 协议1, 协议2, ...
 协议的例  # TODO: Supply [使用协议的例子]
协议与附属型
 附属型的声明
associatedtype 附属型名 = 默认的型

● 可以设定默认的型, 没有声明或者无法推导时使用自动判断为该型

● 构造体, 类, 枚举型内部可以定义新型

● 属于泛型, 型参数

● 编译时候静态解析并替换为具体的型

● 决定具体型的方法

// 以此协议为例
protocol TestProtocol {
associatedtype SampleData //附属型SampleData
var data: SampleData { get set }
}

(a)用typealias给出具体型

struct Sample1: TestProtocol {
typealias SampleData = Int // typealias来决定具体型
...
}

 (b)定义型(内部嵌套的型)来给出定义

struct Sample2: TestProtocol {
struct SampleData { var x: Int, y: Int } // 嵌套型来给出定义, 也就是在内部定义一个和附属型名字一样的型
...
}

 (c)从型的使用方法来推导出型

struct Sample3: TestProtocol {
var data: Double // 根据型推导。因为协议里有var data: SampleData { get set }
...
}
 Self

● 表示采用该协议的型

只能在协议和类中使用

在类中只能作为方法的返回值

● 附属型的表达方法

Self.附属型名

 向类型参数添加限制

● associatedtype A

没有任何限制

● associatedtype A: 协议名

类型A必须采用右侧指定的协议, 多个用逗号,隔开

associatedtype SampleData: Equatable

● associatedtype A: 协议名 where 条件

  多个协议的话where放在最后

类型A必须采用协议, 并且必须满足指定条件(多个条件用,隔开)

条件为

  (1) 型: 协议

   指定的型必须采用右侧协议

associatedtype SampleData: CustomStringConvertible where SampleData: Equatable

  (2) 型1 == 型2

  型1, 型2同型

associatedtype SampleData: CustomStringConvertible where SampleData == String

  (3) 另外继承协议的话, 可以对其他协议的附属型做上述限制

protocol SampleProtocol: SampleParentProtocol, Equatable {
associatedtype SampleData: Equatable where Self.ParentSampleData == String
...
}
   
主要的协议

相等

Equatable

public protocol Equatable {
static func ==(lhs:Self, rhs: Self) -> Bool
}

大小关系

Comparable

public protocol Comparable: Equatable {
public static func <(lhs: Self, rhs: Self) -> Bool
public static func <=(lhs: Self, rhs: Self) -> Bool
public static func >=(lhs: Self, rhs: Self) -> Bool
public static func >(lhs: Self, rhs: Self) -> Bool
}

● 只需要实现==和<

● 采用Comparable的可以使用sorted()来排序

表示序列

Sequence

可以迭代的型(数组, 哈希表, 字符串等)

Sequence协议定义的主要部分

public protocol Sequence {
associatedtype Element // 元素类型
associatedtype Iterator: IteratorProtocol where Iterator.Element == Element // 迭代器
associatedtype SubSequence // 子列型
func makeIterator() -> Iterator // 生成迭代器
func map<T>(_: (Element) throws -> T) rethrows -> [T]
func filter(_: (Element) throws -> Bool) rethrows -> [Element]
func forEach(_ body: (Element) throw -> Void) rethrows
func dropFirst(_ n: Int) -> SubSequence // 去除开头
func dropLast(_ n: Int) -> SubSequence //去除末尾
func prefix(_ maxLength: Int) -> SubSequence // 开头开始的部分列
func suffix(_ maxLength: Int) -> SubSequence // 末尾部分的部分列
}

IteratorProtocol

public protocol IteratorProtocol {
associatedtype Element
mutating func next() -> Self.Element? // 返回一个要素,没了返回nil
}

● 只要自定义makeIterator()就可以采用

  # TODO: Supply [创建采用Sequence的类型]

● 主要方法(数组, 哈希表, 字符串等都可以用), 不含带闭包的方法 # TODO: Supply [补充带闭包的参数 13.4]

  T: 元素的类型(Element), S: 采用Sequence的类型

 比较

elementsEqual(_:S) -> Bool

与参数有同样元素 并且 同样顺序排列返回true

 搜索

contains(_:T) -> Bool

 含有参数元素返回true
 max() -> T?

返回最大的元素

没有元素返回nil

 min() -> T?

返回最小的元素

没有元素返回nil

   
   

部分列

(子列)

 prefix(_:Int) -> S  返回从开头开始的指定元素数量的子列

suffix(_:Int) -> S

 返回到末尾结束的指定元素数量的子列
 dropFirst(_:Int=0) -> S

返回删除开头指定数量元素的子列

不指定则只删除开头

 dropLast(_:Int=0) -> S

返回删除末尾指定数量元素的子列

不指定只删除最后一个

   
 排序  sorted() -> [T]
 返回把把元素从小到大排列的新列
 逆序

reversed() -> [T]

返回倒序的新列

 加索引

enumerated() -> S

返回序号与元素的元组构成的序列

(_:Int, _:Element)

 分割

split(separator: T) -> [S]

通过指定的separator来分割序列,并把结果以数组返回

 连结

joined(separator: String) -> String

元素是字符串时候,返回把所有元素以separator为分隔连结的字符串

   

可以用索引来获取元素

Collection

可以用索引来获取元素的型(数组, 哈希表, 字符串)

● 继承Sequence

● Collection协议定义的主要部分

public protocol Collection: Sequence {
associatedtype Index: Comparable //索引类型
var startIndex: Index { get } // 开头的索引
var endIndex: Index { get } // 末尾的下一个的索引
associatedtype Element // 元素类型
associatedtype IndexDisrance = Int // 索引之间的差
associatedtype Iterator = IndexingIterator<Self> // 迭代器的型
func makeIterator() -> Iterator // 生成迭代器
associatedtype SubSequence: Sequence = Slice<Self>
    where SubSequence.SubSequence == SubSequence,
        Element == SubSequence.Element,
        SubSequence.Index == Index
subscript(position: Index) -> Element { get } // 获取指定索引处的元素
subscript(bounds: Range<Index>) -> SubSequence {get} // 获取指定返回的元素序列
associated Indices: Sequence = DefaultIndices<Self>
where Indices.Element == Element,
Indices.Index == index,
Indices.SubSequence == Indices
var indices: Indices { get } // 有索引组成的序列
func prefix(upTo: Index) -> SubSequence // 指定位置之前的子列
func suffix(from: Index) -> SubSequence // 指定位置开始的子类
var isEmpty: Bool { get } // 是否为空
var count: IndexDistance { get } // 元素数量
var first: Element? { get } // 开头的元素
func index(_:Index, offsetBy: IndexDistance) -> Index // 获取新的索引
func distance(from: Index, to: Index) -> IndexDistance // 索引间的差
}

●  associatedtype IndexDisrance = Int  指定默认型,没有声明且无法推导时候使用该型来作为IndexDisrance

● Index是索引的型,不一定是整数

● 改变collection(改变内部元素)的方法(上面没写), 只有SubSequence和采用Collection的类型相同时才能用

● 主要属性(数组, 哈希表, 字符串等)

T: 元素的类型(Element), S: 采用Sequence的类型, Index: 索引的类型

 索引
 startIndex: Index { get }  返回最初的位置
 endIndex: Index { get }  返回最后的位置的后一个位置
 搜索

first: T? { get }

返回最初的元素, 没有返回nil

 是否为空

isEmpty: Bool { get }

 元素数量  count: Int { get }
 索引列

indices -> S { get }

从开头获取元素索引的序列

   

● 主要方法(数组, 哈希表, 字符串等)

 索引操作
 index(after: Index) -> Index

获取参数后第一个的索引

相当于index(_:index, offset: 1)

 index(_:Index, offset:Int) -> Index

获取参数后第offset个的索引

 distance(from:Index, to:Index) -> Int

获取两个索引之间的差

例:(Index是Int为例)

3和5的话 5-3=2

   
 搜索

index(of: T) -> Index?

返回和参数相同的第一个元素的索引

没有的话返回nil

 子列
 prefix(through: Index) -> S  获取从开头到through位置的子列
 prefix(upto: Index) -> S  获取从开头到through位置前的子列
 suffix(from: Index) -> S  获取从from到末尾的子列
   
   
 删除
 mutating popFirst() -> T?

获取并从collection删除第一个元素

没有的话返回nil

 mutating removeFirst(_:Int)  从开头删除参数指定个数的元素
   
 倒序

reversed() -> [T]

 加索引

enumerated() -> S

返回以索引和元素为元素的元组构成的序列

 分割

split(separator: T) -> [S]

返回以指定元素分割后的序列构成的数组

 连结

joined(separator: String) -> String

元素是字符串时候,返回把所有元素以separator为分隔连结的字符串

   
   

● 管理多个值的协议主要有(不是全部)

Sequence <-- Collection  <-- BidrectionalCollection

               <-- RangeReplaceableCollection

               <-- 其他...

实际开发时候基本上数组(Array)就够用了

# TODO: Supply [序列与闭包的组合, 使程序简洁 s13.4]

   
   
   
值型数据的共有
 Copy-On-Write

● 写时复制, 平时数据交换是指针,只有在需要改写新处或者原处时复制一个新的来写

加快运行速度

● 写时复制相对于直接写的好处是写失败不会对先前版本有影响

 值型数据的共有 

● Swift的值型数据使用Copy-On-Write

● 子列的也是Copy-On-Write

  Sequence, SubSequence      SubSequence基本上和Sequence一样

String, SubString

  Array, ArraySlice

好处: ● 保留共有指针的高速

     ●  防止了因为子列的参照而使得主列无法释放

      因为不同型, 子列变到主列触发Copy机制, 子列与元主列不再被新变量参照

 方针: 每次都变换拖慢运行速度,所以函数的参数, 返回值, 向属性代入等变换为主列

      短期内部处理不用转换

   


Swift4 协议的更多相关文章

  1. Swift4.0复习协议

    1.协议的定义: /// 定义一个协议MyProt protocol MyProt {   /// 声明了一个实例方法foo, /// 其类型为:() -> Void func foo()   ...

  2. XCode10 swift4.2 适配遇到的坑

    以下是2018年10月23日更新 经过大约一个月的时间的适配,项目正式使用XCode10(以下简称为10 or XC10)大部分库都升级为Swift4.2(以下简称为 4.2 or S4.2),下面是 ...

  3. Swift4 扩张(Extenstion), 集合(Set)

    创建: 2018/03/09 完成: 2018/03/10 更新: 2018/04/19 修改小标题  [扩张的定义与使用协议] -> [通过扩张来采用协议] 更新: 2018/09/18 标题 ...

  4. Swift4 类与继承, 类型转换, 类型判断

    创建: 2018/03/05 完成: 2018/03/07 更新: 2018/03/09 完善标题 [Swift4 类与继承, 类型转换] -> [Swift4 类与继承, 类型转换与判断] 补 ...

  5. Swift4 模式, 枚举型

    创建: 2018/03/05 完成: 2018/03/05 更新: 2018/03/10 改变标题 [Swift4 模式] -> [Swift4 模式, 枚举型] 补充RawRepresenta ...

  6. Swift4.0复习特性、编译标志和检查API的可用性

    1.Swift中的特性: @引出,后面紧跟特性名,圆括号带参数即可. @attribute(args) avaiable: 指明对象,函数,类型的可用性. @available(iOS 10.0, m ...

  7. Swift4 - GCD的使用

    Swift4 - GCD的使用 2018年03月30日 17:33:27 Longshihua 阅读数:1165 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csd ...

  8. HTTP协议系列(1)

    一.为什么学习Http协议       首先明白我们为什么学习HTTP协议,也就是说明白HTTP协议的作用.HTTP协议是用于客户端与服务器之间的通讯.明白了HTTP协议的作用也就知道了为什么要学习H ...

  9. 重温Http协议--请求报文和响应报文

    http协议是位于应用层的协议,我们在日常浏览网页比如在导航网站请求百度首页的时候,会先通过http协议把请求做一个类似于编码的工作,发送给百度的服务器,然后在百度服务器响应请求时把相应的内容再通过h ...

随机推荐

  1. Linux中命令选项及参数简介

    登录Linux后,我们就可以在#或$符后面去输入命令,有的时候命令后面还会跟着“选项”(英文options)或“参数”(英文arguments).即Linux中命令格式为: command [opti ...

  2. “亚信科技杯”南邮第七届大学生程序设计竞赛之网络预赛 A noj 2073 FFF [ 二分图最大权匹配 || 最大费用最大流 ]

    传送门 FFF 时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte总提交 : 145            测试通过 : 13 ...

  3. request对象学习

    import java.io.IOException; import java.util.Enumeration; import javax.servlet.ServletException; imp ...

  4. Java中Cookie常用操作类(Spring中操作Cookie)

    说明:Cookie下用Key取值没有快速的方法,只能便利循环去取. 技巧:置0则cookie会立即删除,设置-1,负值则会在关闭浏览器后删除.切记一定要增加路径:setPath("/&quo ...

  5. 虚拟社会(Virtual Society)

    虚拟社会(Virtual Society),又称赛博社会(Cyber Society),是指不同网民之间经由计算机.远程通讯终端等技术设备相互连接起来以进行信息的共享.互动与交流,并在其中进行社会交往 ...

  6. Meteor核心API

    在本教程中,我们将介绍学习Meteor核心API. 如果你想限制代码只在服务器或客户端可以使用下面的代码运行 - meteorApp.js if (Meteor.isClient) { // Code ...

  7. HTML大文件上传(博客迁移)

    Html大文件上传:跳转 通过github和hexo进行搭建博客,主要是在没有网络的时候,可以本地访问,并支持markdown语法. 新博客地址:跳转

  8. poj 2965 The Pilots Brothers&#39; refrigerator(dfs 枚举 +打印路径)

    链接:poj 2965 题意:给定一个4*4矩阵状态,代表门的16个把手.'+'代表关,'-'代表开.当16个把手都为开(即'-')时.门才干打开,问至少要几步门才干打开 改变状态规则:选定16个把手 ...

  9. [TypeScript] Query Properties with keyof and Lookup Types in TypeScript

    The keyof operator produces a union type of all known, public property names of a given type. You ca ...

  10. 在linux命令行中编译和运行java文件

    同时加载编译多个jar包和java文件 在个人平常使用或者当我们把代码部署到linux服务器上的时候,我们经常需要通过命令行编译和运行java文件,网上关于这个的方法大多是通过 javac -cp f ...