1、数据源中的同构与异构

  • 对于 Swift 的集合数据来说,有同构和异构之分。

    • 如果你需要讨论一群鸟类或者一批飞机,那么这样的数据是同构的,比如包含鸟类的数组 [Bird] 和包含飞机的数组 [Airplane]
    • 有时候你想探讨的是这些空中家伙的共性 “飞翔”,因此你的数据源可能同时包含 BirdAirplane,这样的数据源叫做异构数据。

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 同构与异构的更多相关文章

  1. 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 一.安装软件,配置环境,创建 ...

  2. SOA实践之基于服务总线的设计

    在上文中,主要介绍了SOA的概念,什么叫做“服务”,“服务”应该具备哪些特性.本篇中,我将介绍SOA的一种很常见的设计实践--基于服务总线的设计. 基于服务总线的设计 基于总线的设计,借鉴了计算机内部 ...

  3. Oracle数据库迁移到AWS云的方案

    当前云已经成为常态,越来越多的企业希望使用云来增加基础设施的弹性.减轻基础设施的维护压力,运维的成本等.很多企业使用云碰到的难题之一是如何将现有的应用迁移到云上,将现有应用的中间件系统.Web系统及其 ...

  4. Java分布式应用技术架构介绍

    分布式架构的演进 系统架构演化历程-初始阶段架构

  5. 多核处理器基础SMP&AMP&BMP

    多核处理器也称片上多核处理器(Chip Multi-Processor,CMP). 1.多核处理器的流行 多核出现前,商业化处理器都致力于单核处理器的发展,其性能已经发挥到极致,仅仅提高单核芯片的速度 ...

  6. 并行计算基础&编程模型与工具

    在当前计算机应用中,对快速并行计算的需求是广泛的,归纳起来,主要有三种类型的应用需求: 计算密集(Computer-Intensive)型应用,如大型科学project计算与数值模拟: 数据密集(Da ...

  7. 老李分享: 并行计算基础&编程模型与工具 1

    老李分享: 并行计算基础&编程模型与工具   在当前计算机应用中,对高速并行计算的需求是广泛的,归纳起来,主要有三种类型的应用需求: 计算密集(Computer-Intensive)型应用,如 ...

  8. 老李分享: 并行计算基础&编程模型与工具

    在当前计算机应用中,对高速并行计算的需求是广泛的,归纳起来,主要有三种类型的应用需求: 计算密集(Computer-Intensive)型应用,如大型科学工程计算与数值模拟: 数据密集(Data-In ...

  9. Java分布式应用技术架构

    分布式架构的演进 系统架构演化历程-初始阶段架构初始阶段 的小型系统 应用程序.数据库.文件等所有的资源都在一台服务器上通俗称为LAMP特征:应用程序.数据库.文件等所有的资源都在一台服务器上.描述: ...

随机推荐

  1. C#的委托(delegate、Action、Func、predicate)

    委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递.事件是一种特殊的委托. 1.委托的声明 delegate我们常用到的一种声明 delegate至少0个参数,至多32个参 ...

  2. BZOJ 4767 两双手

    题解: 发现这种题目虽然可以想出来,但磕磕碰碰得想挺久的 根据数学可以知道组成方案是唯一的(集合) 然后发现每个使用的大小可能是接近n^2的 直接dp(n^4)是过不了的 那么先观察观察 我们可以把每 ...

  3. python全栈开发day23-面向对象高级:反射(getattr、hasattr、setattr、delattr)、__call__、__len__、__str__、__repr__、__hash__、__eq__、isinstance、issubclass

    一.今日内容总结 1.反射 使用字符串数据类型的变量名来操作一个变量的值. #使用反射获取某个命名空间中的值, #需要 #有一个变量指向这个命名空间 #字符串数据类型的名字 #再使用getattr获取 ...

  4. Codeforces 442C Artem and Array (看题解)

    Artem and Array 经过分析我们能发现, 如果对于一个a[ i ] <= a[ i + 1 ] && a[ i ] <= a[ i - 1 ]可以直接删掉. 最 ...

  5. 决策树分类算法及python代码实现案例

    决策树分类算法 1.概述 决策树(decision tree)——是一种被广泛使用的分类算法. 相比贝叶斯算法,决策树的优势在于构造过程不需要任何领域知识或参数设置 在实际应用中,对于探测式的知识发现 ...

  6. 被忽视的META标签之特效(页面过渡效果)

    在web设计中使用js可以实现很多的页面特效,然而很多人却忽视了HTML标签中META标签的强大功效,其实meta标签也可以实现很多漂亮的页面过渡效果. META标签是HTML语言HEAD区的一个辅助 ...

  7. codeforces 366C Dima and Salad 【限制性01背包】

    <题目链接> 题目大意: 在一个水果篮里有n种水果,并且这些水果每一种都有一个美味度和一个卡路里的属性, 小明要从这些水果中选出来一些做一个水果沙拉, 并且要求他的水果沙拉的美味度是卡路里 ...

  8. anaconda虚拟环境管理,从此Python版本不用愁

    1 引言 在前几篇博文中介绍过virtualenv.virtualenvwrapper等几个虚拟环境管理工具,本篇要介绍的anaconda也有很强大的虚拟环境管理功能,甚至相比virtualenv.v ...

  9. 谈谈MySQL无法连接的原因和分析方法

    [可能的原因] MySQL无法连接的原因有很多,比如: 1.数据库的请求量突增,实例连接数超过max_connections,或用户连接数超过max_user_connections, 这种情况连接时 ...

  10. for循环的灵活性

      for循环把初始化.测试和更新组合在一起,其基本形式如下所示: for(初始化:测试条件:更新表达式) { //循环体 }   关键字for后面的圆括号中3个表达式,分别用两个分号隔开:   第一 ...