Swift 同构与异构
1、数据源中的同构与异构
对于 Swift 的集合数据来说,有同构和异构之分。
- 如果你需要讨论一群鸟类或者一批飞机,那么这样的数据是同构的,比如包含鸟类的数组
[Bird]和包含飞机的数组[Airplane]。 - 有时候你想探讨的是这些空中家伙的共性 “飞翔”,因此你的数据源可能同时包含
Bird和Airplane,这样的数据源叫做异构数据。
- 如果你需要讨论一群鸟类或者一批飞机,那么这样的数据是同构的,比如包含鸟类的数组
1.1 使用协议构建异构数据
协议是描述一个事物属性的最小力度划分,Swift 协议的一个重要作用就是构建异构数据,数组的定义是泛型的,当你把协议作为类型去初始化一个数组的时候,实际是为数组中的成员的泛型定义增加了一层协议的约束。
使用协议实现数据的异构除了功能划分更明确、粒度更小之外,还有一个好处是运行的效率要高于使用类的继承实现的数据异构。Swift 作为一门强类型语言,继承的安全性检查规则比较复杂,运行时的类型转换(特指父类与子类的转换)并不高,而协议不会保存数据,协议的实现只需要参考上下文,所以在运行速度上更胜一筹。使用协议实现异构,者也是苹果官方推荐的写法。
使用协议构建异构数据
// 创建协议 protocol CanFly {
func fly()
} // 创建异构数据源类型 struct Bird: CanFly { var name = "" func fly() {
print("bird fly")
}
} struct Airplane: CanFly { var company = "" func fly() {
print("airplane fly")
}
}
// 创建异构的数组 let flyArray: [CanFly] = [ // 指定数据上下文类型 Bird(name: "maque"),
Airplane(company: "zhongguodongfanghangkong")
] for f in flyArray {
f.fly() // 依次输出:bird fly airplane fly
}
- 由于异构数组可能存在多层共性,所以此时使用类型推断时编译器是无法确定
flyArray的类型的,你需要明确指定异构数组的上下文,这里指定数据源为[CanFly]类型的数组,此时向数组中传入的所有成员类型都必须是遵守CanFly协议的类型实例。 - 异构数据源中的所有数据都可以调用数据类型上下文中的协议所声明的成员。
- 由于异构数组可能存在多层共性,所以此时使用类型推断时编译器是无法确定
1.2 使用协议动态方法构建
上例中方法
fly定义在协议的声明中,所以是一个动态的方法,会完全被协议遵守者重写,无论你是否在协议扩展中给予fly方法默认实现,获得的协议方法都是被重写过的。// 创建协议 protocol CanFly {
func fly()
}
// 创建协议扩展 extension CanFly {
func fly() {
print("can fly")
}
}
// 创建异构数据源类型 struct Bird: CanFly { var name = "" func fly() {
print("bird fly")
}
} struct Airplane: CanFly { var company = "" func fly() {
print("airplane fly")
}
}
// 创建异构的数组 let flyArray: [CanFly] = [ // 指定数据上下文类型 Bird(name: "maque"),
Airplane(company: "zhongguodongfanghangkong")
] for f in flyArray { // 获得的协议方法都是被重写过的
f.fly() // 依次输出:bird fly airplane fly
}
1.3 使用协议静态方法构建
如果上例中方法
fly定义在协议的扩展中,当上下文不为协议CanFly类型时,协议中定义的fly方法会完全被协议遵守者重写;当上下文为协议CanFly类型时,会完全使用默认实现。// 创建协议 protocol CanFly { }
// 创建协议扩展 extension CanFly {
func fly() {
print("can fly")
}
} struct Bird: CanFly { var name = "" func fly() {
print("bird fly")
}
} struct Airplane: CanFly { var company = "" func fly() {
print("airplane fly")
}
}
// 创建异构的数组 let flyArray: [CanFly] = [ // 指定数据上下文类型
Bird(name: "maque"),
Airplane(company: "zhongguodongfanghangkong")
] for f in flyArray { // 获得的协议方法都是被重写过的
f.fly() // 依次输出:can fly can fly
}
1.4 获取异构数据
从异构的数据源中还原真实的数据类型
for f in flyArray { if let bird = f as? Bird {
bird.fly() // bird fly
} else if let airplane = f as? Airplane {
airplane.fly() // airplane fly
}
}
只想确定异构的数据是某个类型的但是却不会用到数据本身
for f in flyArray { if let bird = f as? Bird {
bird.fly() // bird fly
} else if f is Airplane {
print("airplane") // airplane
}
}
is的功能等价于一个匿名的转换过程
if let _ f as? Airplane {
print("airplane")
}
2、AnyObject
AnyObject的存在是为了兼容现有的 OC 和 iOS 的代码,但并不会经常使用它来构建自己的数据类型。在 Swift 2.2 中,
AnyObject变成了一个协议,它既出现在桥接中,又经常被用作定义异构数据。@objc public procotol AnyObject {}
- 不过作为一个协议,
AnyObject仍旧缺少足够的描述,你可以单纯的认为AnyObject是 OC 中id的桥接。
- 不过作为一个协议,
在 Swift 3.0 中,对
AnyObject的功能进行了拆分,AnyObject现在专门用来处理 OC 桥接,Any用来定义异构数据。Storyboard 中会出现
AnyObject,还有在某些函数的参数中可以见到AnyObject。func prepare(for segue: UIStoryboardSegue, sender: Any?)
3、Any
- 在 Swift 3.0 中,对
AnyObject的功能进行了拆分,AnyObject现在专门用来处理 OC 桥接,Any用来定义异构数据。
3.1 Any 的使用
因为
Any是一种未知类型的协议,所以不能向它发送任何消息,为了使用它需要把它转换成一种我们知道的类型。- 我们可以定义一个已知类型的变量,然后使用
变量 = AnyObject 转换后的东西。
- 我们可以定义一个已知类型的变量,然后使用
和其它协议一样,处理
AnyObject时可以使用as?、as!或者is。@IBAction func appendDigit(sender: Any) { if let mysender = sender as? UIButton { // 再进行对按钮的操作,使用 mysender
}
}
3.2 Any 与 id 的对比
如果你的 Swift 代码中使用了 OC 的 API,OC 中的
id在 Swift 中会被桥接成Any,和id一样,声明成Any的对象可以使用不同的构造器进行初始化。var someObject: Any = UIColor.red
someObject = NSDate()
- 声明为
Any的对象既可以成为一个颜色,又可以成为一个日期。
- 声明为
无论你的
someObject当前是什么类型,都可以调用 swift 中的任意方法,编译器不会检查someObject的类型,someObject的真实类型直到运行时才会揭晓。使用Any类型时编译会报错。var someObject: AnyObject = UIColor.red
someObject = NSDate() someObject.withAlphaComponent(0.5)
someObject.timeIntervalSinceNow
someObject.append("abc")
为了写出更加安全的代码,推荐把
Any类型转换成真正的类型使用,引入编译器的检查。
Swift 同构与异构的更多相关文章
- OGG同构(ORACLE-ORACLE)、异构(ORACLE-MYSQL)同步配置及错误解析
环境:11.2.0.3(已安装数据库实例)+OEL5.7 192.168.1.55 zlm sid:zlm11g 192.168.1.60 zlm2 sid:zlm11g 一.安装软件,配置环境,创建 ...
- SOA实践之基于服务总线的设计
在上文中,主要介绍了SOA的概念,什么叫做“服务”,“服务”应该具备哪些特性.本篇中,我将介绍SOA的一种很常见的设计实践--基于服务总线的设计. 基于服务总线的设计 基于总线的设计,借鉴了计算机内部 ...
- Oracle数据库迁移到AWS云的方案
当前云已经成为常态,越来越多的企业希望使用云来增加基础设施的弹性.减轻基础设施的维护压力,运维的成本等.很多企业使用云碰到的难题之一是如何将现有的应用迁移到云上,将现有应用的中间件系统.Web系统及其 ...
- Java分布式应用技术架构介绍
分布式架构的演进 系统架构演化历程-初始阶段架构
- 多核处理器基础SMP&&BMP
多核处理器也称片上多核处理器(Chip Multi-Processor,CMP). 1.多核处理器的流行 多核出现前,商业化处理器都致力于单核处理器的发展,其性能已经发挥到极致,仅仅提高单核芯片的速度 ...
- 并行计算基础&编程模型与工具
在当前计算机应用中,对快速并行计算的需求是广泛的,归纳起来,主要有三种类型的应用需求: 计算密集(Computer-Intensive)型应用,如大型科学project计算与数值模拟: 数据密集(Da ...
- 老李分享: 并行计算基础&编程模型与工具 1
老李分享: 并行计算基础&编程模型与工具 在当前计算机应用中,对高速并行计算的需求是广泛的,归纳起来,主要有三种类型的应用需求: 计算密集(Computer-Intensive)型应用,如 ...
- 老李分享: 并行计算基础&编程模型与工具
在当前计算机应用中,对高速并行计算的需求是广泛的,归纳起来,主要有三种类型的应用需求: 计算密集(Computer-Intensive)型应用,如大型科学工程计算与数值模拟: 数据密集(Data-In ...
- Java分布式应用技术架构
分布式架构的演进 系统架构演化历程-初始阶段架构初始阶段 的小型系统 应用程序.数据库.文件等所有的资源都在一台服务器上通俗称为LAMP特征:应用程序.数据库.文件等所有的资源都在一台服务器上.描述: ...
随机推荐
- [解决]IP地址非法,请接入联通热点后重新获取
在使用联通chinaunicom WLAN上网时,在弹出的登陆界面后输入账号.密码,点登陆,显示IP地址非法,请接入联通热点后重新获取.现在在其他地方看到解决办法连接chinaunicom,弹出登陆界 ...
- 记录weiye项目上线遇到的一些问题
1.使用vpn访问客户内网 参考:http://jingyan.baidu.com/article/a3f121e4f9903cfc9052bb0b.html 2.设置使用ip地址直接访问项目(之后可 ...
- Codeforces Round #317 (div 2)
Problem A Arrays 思路:水一水. #include<bits/stdc++.h> using namespace std; ; int n1,n2,k,m,a[N],b[N ...
- 非常可乐 HDU1495
BFS题 一共有六种状态转移 一一枚举就好 设置一个标记数组. 用二重循环可以很清晰的解决代码长的问题 #include<cstdio> #include<cstring> # ...
- set 集合的知识
1. 定义: 2. 集合的交集,并集,差集: 3. 集合添加add(无序): 4. 添加可迭代对象(字符串,列表,元组)update: 字符串实例: 5. 删除元素( pop , remove ): ...
- 《Gradle权威指南》--Java Gradle插件
No1: dependencies{ compile group: 'com.squareup.okhttp3',name:'okhttp',version:'3.0.1' } //缩写 depend ...
- Vscode下Python的用户界面介绍
Visual Studio Code的核心是代码编辑器.与许多其他代码编辑器一样,VS Code在左侧采用通用用户界面和浏览器布局,显示您可以访问的所有文件和文件夹,右侧显示编辑器,显示已打开文件的内 ...
- 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-1 蒙特卡罗 (一)
今天起,我们就开始学习第三本书了 这本书主要讲的是蒙特卡罗渲染,以及相关的数学.术语概念等 这本书相较于前面两本有着什么不同,承担着什么样的任务,尚涉书未深,姑妄言之: 第一本书,带领我们初探光线追踪 ...
- 在网站中使用Bing Translator插件翻译文章。
前一阵子给项目增加了翻译的功能,用的是Bing Translator Widget,今天看见有个兄弟写自定义自己的博客,我就尝试着把这个插件加到了自己的博客中.还真的好用.大家先看下效果,觉得好的请继 ...
- 数码管应用digital_pile
#include "reg52.h" #include "digital_pile.h" void main(){ //P0 = 0x00; //P2 = 0x ...