原文:http://www.cocoachina.com/applenews/devnews/2014/0623/8923.html

Swift 事实上是支持反射的。只是功能略弱。

本文介绍主要的反射使用方法和相关类型。

 
MetaType 和 Type 语法
The metatype of a class, structure, or enumeration type is the name of that type followed by .Type. The metatype of a protocol type—not the concrete type that conforms to the protocol at runtime—is the
name of that protocol followed by .Protocol. For example, the metatype of the class type SomeClass is SomeClass.Type and the metatype of the protocol SomeProtocol is SomeProtocol.Protocol.
 
You can use the postfix self expression to access a type as a value. For example, SomeClass.self returns SomeClass itself, not an instance of SomeClass. And SomeProtocol.self returns SomeProtocol itself,
not an instance of a type that conforms to SomeProtocol at runtime.
  • metatype-type –> type.Type | type.Protocol
  • type-as-value –> type.self
 
当中 metatype-type 出如今代码中须要类型的地方, type-as-value 出如今代码中须要值、变量的地方。
 
Any.Type 类型大家能够猜下它表示什么。
 
基础定义
 
反射信息用 Mirror 类型表示,类型协议是 Reflectable,但实际看起来 Reflectable 没有不论什么作用。


  1. protocol Reflectable { 
  2.   func getMirror() -> Mirror 
  3. protocol Mirror { 
  4.   var value: Any { get } 
  5.   var valueType: Any.Type { get } 
  6.   var objectIdentifier: ObjectIdentifier? { get } 
  7.   var count: Int { get } 
  8.   subscript (i: Int) -> (String, Mirror) { get } 
  9.   var summary: String { get } 
  10.   var quickLookObject: QuickLookObject? { get } 
  11.   var disposition: MirrorDisposition { get } 
 
实际上全部类型都实现了 Reflectable。
 
Mirror 协议相关字段:
  • 1.value 相当于变量的 as Any 操作
  • 2.valueType 获得变量类型
  • 3.objectIdentifier 相当于一个 UInt 作用未知。可能是 metadata 表用到
  • 4.count 子项目个数(能够是类、结构体的成员变量。也能够是字典,数组的数据)
  • 5.subscript(Int) 訪问子项目, 和子项目的名字
  • 6.summary 相当于 description
  • 7.quickLookObject 是一个枚举,这个在 WWDC 有讲到,就是 Playground 代码右边栏的显示内容,比方常见类型,颜色。视图都能够
  • 8.disposition 表示变量类型的性质,基础类型 or 结构 or 类 or 枚举 or 索引对象 or … 例如以下

  1. enum MirrorDisposition { 
  2.   case Struct // 结构体 
  3.   case Class // 类 
  4.   case Enum // 枚举 
  5.   case Tuple // 元组 
  6.   case Aggregate // 基础类型 
  7.   case IndexContainer // 索引对象 
  8.   case KeyContainer // 键-值对象 
  9.   case MembershipContainer // 未知 
  10.   case Container // 未知 
  11.   case Optional // Type? 
  12.   var hashValue: Int { get } 
通过函数 func reflect<T>(x: T) -> Mirror 能够获得反射对象 Mirror 。它定义在 Any 上。全部类型均可用。
 
实际操作
 
.valueType 处理
Any.Type 是全部类型的元类型,所以 .valueType 属性表示类型。实际使用的时候还真是有点诡异:

  1. let mir = reflect(someVal) 
  2. swift mir.valueType { 
  3. case _ as String.Type: 
  4.     println("type = string") 
  5. case _ as Range<Int>.Type: 
  6.     println("type = range of int") 
  7. case _ as Dictionary<Int, Int>.Type: 
  8.     println("type = dict of int") 
  9. case _ as Point.Type: 
  10.     println("type = a point struct") 
  11. default: 
  12.     println("unkown type") 
  13. }     
 
或者使用 is 推断:

  1. if mir is String.Type { 
  2.     println("!!!type => String") 
is String 推断变量是否是 String 类型。而 is String.Type 这里用来推断类型是否是 String 类型。

 
subscript(Int) 处理
实測发现直接用 mir[0] 訪问偶尔会出错。或许是 beta 的原因。

  1. for r in 0..mir.count { 
  2.     let (name, subref) = mir[r] 
  3.     prtln("name: \(name)") 
  4.     // visit sub Mirror here 
通过上面的方法,基本上能够遍历大部分结构。
 
不同类型的处理
 
Struct 结构体、 Class 类
  • .count 为字段个数。
  • subscript(Int) 返回 (字段名,字段值反射 Mirror) 元组
  • summary 为 mangled name
  •  
Tuple 元组
  • .count 为元组子元素个数
  • subscript(Int) 的 name 为 “.0”, “.1” …
  •  
Aggregate 基础类型
包含数字、字符串(含 NSString)、函数、部分 Foundation 类型、 MetaType 。
 
非常奇怪一点是測试发现枚举也被反射为基础类型。

怀疑是没实现完。

  • .count 为 0
 
IndexContainer 索引对象
包含 Array<T>, T[], NSArray 等。能够通过 subscript 訪问。

  • .count 为元组子元素个数
  • subscript(Int) 的 name 为 “[0]”, “[1]” …
 
KeyContainer 键-值对象
包含 Dictionary<T, U>、NSDictionary
  • .count 为元组子元素个数
  • subscript(Int) 的 name 为 “[0]”, “[1]” … 实际訪问是 (name, (reflect(key), reflect(val)))
 
Optional Type?
仅仅包含 Type?

,不包含 Type!。

  • .count 为 0 或者 1 (相应 nil 和有值的情况)
  • subscript(Int) , name 为 “Some”
 
其它
Enum 枚举 看起来是未使用
MembershipContainer // 未知
Container // 未知
 
演示样例代码
 Gist  
 
 
 
我这里再补充几句。

由于考虑到有些编程经验不是非常丰富的朋友对于此问题可能会感觉比較迷糊。

楼主,贴了Apple官方Swift编程指南与编程手冊第791页的第二段。

事实上第一段也比較重要——

 
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
 
一个元类型是对任一类型(包含类类型,结构类型。枚举类型以及协议类型)的类型的引用。

 
在动态编程语言中,其复合类型(比方Swift中的类类型,结构类型。枚举类型以及协议类型)一般会以某种编码方式记录在执行时内存中,然后对外接口提供每种类型的唯一签名句柄。

 
举一个非常easy的样例。大家玩过Objective-C的话。[NSString class]所返回的Class句柄就是NSString的元类型。然后,我们通过runtime提供的各种接口就能够做非常多事情。

比方:


  1. Class strClass = [NSString class]; 
  2.     NSLog(@"The class name is: %s.", class_getName(strClass)); 
上述代码将输出The class name is NSString.
 
对于像Objective-C以及Swift这样的比較动态的编程语言而言,元类型事实上就是桥接我当前静态代码与执行时类型进行交互的玩意儿。通过元类型,我除了能够查询所相应的类型的具体信息之外,甚至还能对已存在的类型进行改动。

比方改动成员属性、甚至替换成员方法的实现等。这样的功能特性在计算机编程语言中也被称作为反射--Reflection。

 

Swift中的反射的更多相关文章

  1. Swift Swift中的反射

    Swift的反射机制是基于一个叫 Mirror 的 struct 来实现的,其内部有如下属性和方法: let children: Children //对象的子节点. displayStyle: Mi ...

  2. 思考 Swift 中的 MirrorType 协议

    Swift中的反射非常有限,仅允许以只读方式访问元数据的类型子集.或许 Swift 因有严格的类型检验而不需要反射.编译时已知各种类型,便不再需要进行进一步检查或区分.然后大量的 Cocoa API ...

  3. 阿里巴巴最新开源项目 - [HandyJSON] 在Swift中优雅地处理JSON

    项目名称:HandyJSON 项目地址:https://github.com/alibaba/handyjson 背景 JSON是移动端开发常用的应用层数据交换协议.最常见的场景便是,客户端向服务端发 ...

  4. swift中的结构体和枚举

    Swift 里的结构体非常特殊. 类是面向对象编程语言中传统的结构单元.和结构体相比,Swift 的类支持实现继承,(受限的)反射,析构函数和多所有者. 既然类比结构体强大这么多,为什么还要使用结构体 ...

  5. Swift 中枚举

    Swift 中枚举高级用法及实践 字数11017 阅读479 评论0 喜欢20 title: "Swift 中枚举高级用法及实践"date: 2015-11-20tags: [AP ...

  6. swift 中关于open ,public ,fileprivate,private ,internal,修饰的说明

    关于 swift 中的open ,public ,fileprivate,private, internal的区别 以下按照修饰关键字的访问约束范围 从约束的限定范围大到小的排序进行说明 open,p ...

  7. 详解C#中的反射

    反射(Reflection) 2008年01月02日 星期三 11:21 两个现实中的例子:1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内脏的生理情况.这是如何做到的呢?B超是B ...

  8. Swift中的可选链与内存管理(干货系列)

    干货之前:补充一下可选链(optional chain) class A { var p: B? } class B { var p: C? } class C { func cm() -> S ...

  9. 在Swift中实现单例方法

    在写Swift的单例方法之前可以温习一下Objective-C中单例的写法: + (instancetype)sharedSingleton{ static id instance; static d ...

随机推荐

  1. 利用Redis发布订阅完成tomcat集群下的消息通知

    以下为个人想法,如果有说的不对的地方请各位大佬见谅! 这是博主的第一篇博客,可能排版以及一些描述有不合理的地方还请勿喷,希望大家尽可能的多给我这样的新人一些鼓励让我能在写博客的道路上走下去. 进入正题 ...

  2. PHP语言的优缺点

    PHP是一种跨平台的服务器端的嵌入式脚本语言. 优点: 实用性强 它大量地借用C.Java 平台广 支持数据种类多 有成熟框架 ,面向对象体系 PHP是完全免费 开源 缺点: 语法不严谨, 弱类型语言 ...

  3. python数据类型之内置方法

    python有六大数据类型,分别为整型.字符串.列表.字典.元祖和集合,这些基本数据类型都内置了很多方法,接下来一一探寻. python中整型有两种:int和float 1 int 使用dir函数查看 ...

  4. FTP 150 Opening BINARY mode data connection for MLSD 读取目录列表失败

    这完全是因为防火墙的问题,把服务器的防火墙关闭之后,在连接,一切ok

  5. 关于eclipse项目的x号报错的一些问题

    有些时候项目中并未有什么问题 但项目前会有一个X号报错且无法运行项目 我们不妨从jre和Tomcat的一些配置中找原因 1,首先查看jre的安装是否正确,可以看见并未出错 ,如果有问题,重新导入一下即 ...

  6. 【java工具】java常用工具

    java反编译工具 可以将看不懂的.class文件转换成看得懂的.java文件,这样一来就能很方便的读懂别人编写的java代码. findbugs FindBugs-IDEA插件的使用 阿里巴巴Jav ...

  7. 关于IOS下click事件委托失效的解决方案

    一.由于某些特殊情况下,需要用到事件委托,比如给动态创建的DOM绑定click事件,这里就需要事件委托(这里就牵扯到:目标元素和代理元素)目标元素:动态创建的元素,最终click事件需要绑定到该元素 ...

  8. HDU4825(01字典树)

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)Total S ...

  9. linux学习笔记-lrmi源码包的编译安装方法

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 官方的lrmi包没有人更新了,如果碰到需要这个编译安装这个包,可以参考我的解决思路,如下: https://pkgs.org/这 ...

  10. python中收集函数的解包问题

    收集参数的解包问题 - 把参数放入list或者字典中,直接把list/dict中的值放入收集参数中- 语法:参照案例 # 收集参数的问题 def stu(*args): print("=&q ...