Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)
对于C#、Java开发人员来说,肯定都对反射这个概念相当熟悉。所谓反射就是可以动态获取类型、成员信息,同时在运行时(而非编译时)可以动态调用任意方法、属性等行为的特性。
在使用ObjC开发时很少强调其反射概念,因为ObjC的Runtime要比其他语言中的反射强大的多。在ObjC中可以很简单的实现字符串和类型的转换(NSClassFromString()),实现动态方法调用(performSelector: withObject:),动态赋值(KVC)等等。
在Swift中并不提倡使用Runtime,而是像其他语言一样使用反射(Reflect)。当然,目前Swift中的反射还没有其他语言中的反射功能强大,不仅远不及OC的Runtime,离Java的反射也有一定的距离。
Swift的反射机制是基于一个叫 Mirror 的 struct 来实现的,其内部有如下属性和方法:
|
1
2
3
4
|
let children: Children //对象的子节点。displayStyle: Mirror.DisplayStyle? //对象的展示风格let subjectType: Any.Type //对象的类型func superclassMirror() -> Mirror? //对象父类的 mirror |
4,Swift反射的使用样例
|
1
2
3
4
5
6
7
|
//用户类class User { var name:String = "" //姓名 var nickname:String? //昵称 var age:Int? //年龄 var emails:[String]? //邮件地址} |
接着创建一个用户对象,并通过反射获取这个对象的信息:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
//创建一个User实例对象let user1 = User()user1.name = "hangge"user1.age = 100user1.emails = ["hangge@hangge.com","system@hangge.com"] //将user对象进行反射let hMirror = Mirror(reflecting: user1) print("对象类型:\(hMirror.subjectType)")print("对象子元素个数:\(hMirror.children.count)") print("--- 对象子元素的属性名和属性值分别如下 ---")for case let (label?, value) in hMirror.children { print("属性:\(label) 值:\(value)")} |
控制台输出信息如下:

|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//根据属性名字符串获取属性值func getValueByKey(obj:AnyObject, key: String) -> Any { let hMirror = Mirror(reflecting: obj) for case let (label?, value) in hMirror.children { if label == key { return unwrap(value) } } return NSNull()}//将可选类型(Optional)拆包func unwrap(any:Any) -> Any { let mi = Mirror(reflecting: any) if mi.displayStyle != .Optional { return any } if mi.children.count == 0 { return any } let (_, some) = mi.children.first! return some} |
下面是实际测试样例,同样用上例的User对象做测试:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
//创建一个User实例对象let user1 = User()user1.name = "hangge"user1.age = 100user1.emails = ["hangge@hangge.com","system@hangge.com"]//通过属性名字符串获取对应的值let name = getValueByKey(user1, key: "name")let nickname = getValueByKey(user1, key: "nickname")let age = getValueByKey(user1, key: "age")let emails = getValueByKey(user1, key: "emails")let tel = getValueByKey(user1, key: "tel")print(name, nickname, age, emails, tel)//当然对于获取到的值也可以进行类型判断if name is NSNull { print("name这个属性不存在")}else if (name as? AnyObject) == nil { print("name这个属性是个可选类型,且为nil")}else if name is String { print("name这个属性String类型,其值为:\(name)")}if nickname is NSNull { print("nickname这个属性不存在")}else if (nickname as? AnyObject) == nil { print("nickname这个属性是个可选类型,且为nil")}else if nickname is String { print("nickname这个属性String类型,其值为:\(nickname)")}if tel is NSNull { print("tel这个属性不存在")}else if (tel as? AnyObject) == nil { print("tel这个属性是个可选类型,且为nil")}else if tel is String { print("tel这个属性String类型,其值为:\(tel)")} |
控制台输出信息如下:

(注意:正由于KVC是基于Objective-C的,所以其不支持可选类型(optional)的属性,比如上例的 var age:Int?
因此用户类做如下改造:)
|
1
2
3
4
5
6
7
|
//用户类class User: NSObject{ var name:String = "" //姓名 var nickname:String? //昵称 var age:Int = 0 //年龄 var emails:[String]? //邮件地址} |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
//创建一个User实例对象let user1 = User()user1.name = "hangge"user1.age = 100user1.emails = ["hangge@hangge.com","system@hangge.com"]//使用KVC取值let name = user1.valueForKey("name")let nickname = user1.valueForKey("nickname")let age = user1.valueForKey("age")let emails = user1.valueForKey("emails")//let tel = user1.valueForKey("tel")print(name, nickname, age, emails) //当然对于获取到的值也可以进行类型判断if name == nil { print("name这个属性是个可选类型,且为nil")}else if name is String { print("name这个属性String类型,其值为:\(name)")} if nickname == nil { print("nickname这个属性是个可选类型,且为nil")}else if nickname is String { print("nickname这个属性String类型,其值为:\(nickname)")} |
|
1
2
3
4
5
6
7
8
9
|
//创建一个User实例对象let user1 = User()//使用KVC赋值user1.setValue("hangge", forKey: "name")user1.setValue(100, forKey: "age")user1.setValue(["hangge@hangge.com","system@hangge.com"], forKey: "emails") print(user1.name, user1.nickname, user1.age, user1.emails) |
原文出自:www.hangge.com 转载请保留原文链接:http://www.hangge.com/blog/cache/detail_976.html
http://www.hangge.com/blog/cache/detail_976.html
Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)的更多相关文章
- ArcSDE SDK For Java二次开发介绍、演示样例
在一个工作中,遇到了须要java后台来查询ArcGIS 中用到的Oracle数据库空间数据,因为对ArcGIS空间数据首次接触,仅仅知道Oracle能够使用ST_GEOMETRY字段存储,例如以下图 ...
- Request介绍及演示样例 PART1
Request在ServletAPI的规范连接地址http://blog.csdn.net/zghwaicsdn/article/details/51035146 HTTP简介 URL是浏览器寻找信息 ...
- C# 反射(Reflection)技术
本文参考自C#反射(Reflection)详解,纯属学习笔记,加深记忆 在介绍反射前,先介绍一个重要的知识点 .Net应用程序是由程序集(Assembly).模块(Module).类型 ...
- Java连接redis的使用演示样例
Java连接redis的使用演示样例 Redis是开源的key-value存储工具,redis通经常使用来存储结构化的数据,由于redis的key能够包括String.hash.listset和sor ...
- 通过Canvas及File API缩放并上传图片完整演示样例
创建一个只管的用户界面,并同意你控制图片的大小.上传到server端的数据,并不须要处理enctype为 multi-part/form-data 的情况.只一个简单的POST表单处理程序就能够了. ...
- Android设计模式之中的一个个样例让你彻底明确装饰者模式(Decorator Pattern)
导读 这篇文章中我不会使用概念性文字来说明装饰者模式.由于通常概念性的问题都非常抽象.非常难懂.使得读者非常难明确究竟为什么要使用这样的设计模式.我们设计模式的诞生,肯定是前辈们在设计程序的时候遇到了 ...
- STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- Swift - 委托(delegate)的介绍,及使用样例
1,委托的说明 委托(delegate)是Cocoa的一个术语,表示将一个对象的部分功能转交给另一个对象. 比如对象A希望对象B知道将要发生或已经发生某件事情,对象A可以把对象B的引用存为一个实例变量 ...
- [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦
[.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...
随机推荐
- 在oracle中将某个字段的数据作为列名的查询
原表结构 查询语句: select sno,sname,sum(语文) 语文,sum(数学) 数学,sum(英语) 英语 from (select sno,sname,decode(subjiect, ...
- Parsing error: The keyword 'export' is reserved && error Parsing error: Unexpected token <
如果你也在使用eslint,也报了如上错误,可以尝试: $ npm install babel-eslint --save-dev 然后,加上: rules: { "parser" ...
- <a>标签中的href伪协议 标签: html 2016-12-24 22:38 365人阅读 评论(0)
<a id="jsPswEdit" class="set-item" href="javascript:;">修改密码</ ...
- 我的网站恢复访问了,http://FansUnion.cn
博客网站 http://FansUnion.cn 恢复访问了. 周末,发表几篇原创文章.
- 0227浅谈MySQL之 Handler_read_*参数
转自博客http://www.path8.net/tn/archives/5613 1.监控语法: 在MySQL里,使用SHOW STATUS查询服务器状态,语法一般来说如下: SHOW [GLOBA ...
- Mycat连接数据库之后导致表名全小写的问题分析研究
初步研究:通过部署发现在Mycat中部署逻辑表表名大小写混合时,在Mycat连接后出现全变小.容易造成错误逻辑表(按混合表名创建物理表): 可能拯救的方法: 1.Linux下部署安装MySQL,默认不 ...
- iOS_网络请求_代理方式
#pragma mark - 网络请求代理方式(异步) - (IBAction)DelegateButtonDidClicked:(UIButton *)sender { // 1.拼接 urlStr ...
- uva:10763 - Foreign Exchange(排序)
题目:10763 - Foreign Exchange 题目大意:给出每一个同学想要的交换坐标 a, b 代表这位同学在位置a希望能和b位置的同学交换.要求每一位同学都能找到和他交换的交换生. 解题思 ...
- [Javascript Crocks] Recover from a Nothing with the `alt` method
Once we’re using Maybes throughout our code, it stands to reason that at some point we’ll get a Mayb ...
- Mac上搭建android环境:Android Studio+GreenVPN
1.下载Android Studio,https://developer.android.com/sdk/index.html 2.使用GreenVPN,感觉还能够.18/月.http://www.g ...