博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Swift中的反射
阅读量:7091 次
发布时间:2019-06-28

本文共 4422 字,大约阅读时间需要 14 分钟。

hot3.png

原文: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 没有任何作用。

protocol Reflectable {   func getMirror() -> Mirror } protocol Mirror {   var value: Any { get }   var valueType: Any.Type { get }   var objectIdentifier: ObjectIdentifier? { get }   var count: Int { get }   subscript (i: Int) -> (String, Mirror) { get }   var summary: String { get }   var quickLookObject: QuickLookObject? { get }   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 … 如下

enum MirrorDisposition {   case Struct // 结构体   case Class // 类   case Enum // 枚举   case Tuple // 元组   case Aggregate // 基础类型   case IndexContainer // 索引对象   case KeyContainer // 键-值对象   case MembershipContainer // 未知   case Container // 未知   case Optional // Type?   var hashValue: Int { get } }

通过函数 func reflect<T>(x: T) -> Mirror 可以获得反射对象 Mirror 。它定义在 Any 上,所有类型均可用。

 

实际操作

 

.valueType 处理

Any.Type 是所有类型的元类型,所以 .valueType 属性表示类型。实际使用的时候还真是有点诡异:

let mir = reflect(someVal) swift mir.valueType { case _ as String.Type:     println("type = string") case _ as Range
.Type:     println("type = range of int") case _ as Dictionary
.Type:     println("type = dict of int") case _ as Point.Type:     println("type = a point struct") default:     println("unkown type") }

 

或者使用 is 判断:

if mir is String.Type {     println("!!!type => String") }

is String 判断变量是否是 String 类型,而 is String.Type 这里用来判断类型是否是 String 类型。

 

subscript(Int) 处理

实测发现直接用 mir[0] 访问偶尔会出错,也许是 beta 的原因。

for r in 0..mir.count {     let (name, subref) = mir[r]     prtln("name: \(name)")     // 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 // 未知

 

示例代码

  

 

 

zenny_chen补充()

 

我这里再补充几句。因为考虑到有些编程经验不是很丰富的朋友对于此问题可能会感觉比较迷糊。

楼主,贴了Apple官方Swift编程指南与编程手册第791页的第二段。其实第一段也比较重要——

 

A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.

 

一个元类型是对任一类型(包括类类型,结构类型,枚举类型以及协议类型)的类型的引用。

 

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

 

举一个非常简单的例子。大家玩过Objective-C的话,[NSString class]所返回的Class句柄就是NSString的元类型。然后,我们通过runtime提供的各种接口就可以做很多事情。比如:

Class strClass = [NSString class];     NSLog(@"The class name is: %s.", class_getName(strClass));

上述代码将输出The class name is NSString.

 

对于像Objective-C以及Swift这种比较动态的编程语言而言,元类型其实就是桥接我当前静态代码与运行时类型进行交互的玩意儿。通过元类型,我除了能够查询所对应的类型的详细信息之外,甚至还能对已存在的类型进行修改。比如修改成员属性、甚至替换成员方法的实现等。这种功能特性在计算机编程语言中也被称作为反射--Reflection。 

转载于:https://my.oschina.net/sunqichao/blog/283567

你可能感兴趣的文章
工控系统安全问题汇总(一)
查看>>
4、SpringBoot------邮件发送(2)
查看>>
无耻上海电信,尽然插广告!!!
查看>>
java创建二叉树并递归遍历二叉树
查看>>
JSON必知必会
查看>>
安全站点导航
查看>>
Oracle Job
查看>>
收集一些有意思的ASCII程序注释(持续收集中,希望大家踊跃贡献)
查看>>
做网站的各种推荐网
查看>>
CS文件密码加密类
查看>>
leetcode 10. 正则表达式匹配
查看>>
JM8.6中帧内帧间模式的选择
查看>>
测试覆盖率工具:EclEmma
查看>>
《CLR via C#》读书笔记 之 基元类型、引用类型和值类型
查看>>
BOS常用代码说明
查看>>
第111天:Ajax之jQuery实现方法
查看>>
/etc/rc.d/init.d/iptables: No such file or directory 错误原因
查看>>
背包问题
查看>>
模拟地与数字地(转)
查看>>
一本审视自己和充满为人处世哲学的书--<<人性的弱点>>
查看>>