ios开发之Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)

1,反射(Reflection)
对于C#、Java开发人员来说,肯定都对反射这个概念相当熟悉。所谓反射就是可以动态获取类型、成员信息,同时在运行时(而非编译时)可以动态调用任意方法、属性等行为的特性。
以Java上的两个知名框架(hibernate和spring)为例。hibernate的属性映射就是通过反射来赋值的,spring的bean的创建就是根据配置的class来反射构建的。

2,Objective-C 的 Runtime
在使用ObjC开发时很少强调其反射概念,因为ObjC的Runtime要比其他语言中的反射强大的多。在ObjC中可以很简单的实现字符串和类型的转换(NSClassFromString()),实现动态方法调用(performSelector: withObject:),动态赋值(KVC)等等。

3,Swift中的反射
在Swift中并不提倡使用Runtime,而是像其他语言一样使用反射(Reflect)。当然,目前Swift中的反射还没有其他语言中的反射功能强大,不仅远不及OC的Runtime,离Java的反射也有一定的距离。
Swift的反射机制是基于一个叫 Mirror 的 struct 来实现的,其内部有如下属性和方法:

let children: Children   //对象的子节点。
displayStyle: Mirror.DisplayStyle?   //对象的展示风格
let subjectType: Any.Type   //对象的类型
func superclassMirror() -> Mirror?   //对象父类的 mirror

4,Swift反射的使用样例

样例1:输出实体对象的类名,属性个数,以及所有属性的属性名和属性值。
首先定义一个用户类:

//用户类
class User {
    var name:String = ""  //姓名
    var nickname:String?  //昵称
    var age:Int?   //年龄
    var emails:[String]?  //邮件地址
}

接着创建一个用户对象,并通过反射获取这个对象的信息:

//创建一个User实例对象
let user1 = User()
user1.name = "hangge"
user1.age = 100
user1.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)")
}

控制台输出信息如下: 

 

样例2:通过属性名(字符串)获取对应的属性值,并对值做类型判断(包括是否为空)
首先为方便使用,这里定义两个方法。getValueByKey()是用来根据传入的属性名字符串来获取对象中对应的属性值。unwrap()是用来给可选类型拆包的(对于非可选类型则返回原值)

//根据属性名字符串获取属性值
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对象做测试:

//创建一个User实例对象
let user1 = User()
user1.name = "hangge"
user1.age = 100
user1.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访问属性值
KVC是key-value coding的缩写。它是一种间接访问对象的机制。其本质是依据OC中Runtime的强大动态能力来实现的。在Swift中,只要类继承NSObject即可使用KVC。(有一个叫KVO的,它又是基于KVC,大家有兴趣的可以自行研究下。)
KVC中:key的值就是属性名称的字符串,返回的value是任意类型,需要自己转化为需要的类型。
(注意:正由于KVC是基于Objective-C的,所以其不支持可选类型(optional)的属性,比如上例的 var age:Int?
因此用户类做如下改造:)

//用户类
class User: NSObject{
    var name:String = ""  //姓名
    var nickname:String?  //昵称
    var age:Int = 0  //年龄
    var emails:[String]?  //邮件地址
}

KVC主要就是两个方法:

(1)通过key获得对应的属性值

//创建一个User实例对象
let user1 = User()
user1.name = "hangge"
user1.age = 100
user1.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)")
}

(2)通过key设置对应的属性值

//创建一个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

时间: 2024-10-27 17:22:43

ios开发之Swift - 反射(Reflection)的介绍与使用样例(附KVC介绍)的相关文章

ios开发之Swift - 点击状态栏使tableView返回顶部(附:状态栏点击事件响应)

1,当页面上只有一个scrollView,点击状态栏scrollView会自动滚动到顶部   比如页面上只有一个表格(UITableView),当点击顶部状态条后,表格会像QQ.微信联系人列表那样回到最上面.   这个是iOS系统默认就有的.   开发之Swift - 点击状态栏使tableView返回顶部(附:状态栏点击事件响应)-swift ios开发教程"> 2,当页面上有多个scrollView,点击状态栏时,视图都不会滚动 这时我们需要把不需要滚动的 scrollView 的 s

ios开发之Swift使用AirPrint进行打印

使用 AirPrint 可以轻松地从 iOS 和 OS X app 中传输无损照片和文稿打印.当然,打印机也要支持AirPrint 技术才行.下面通过样例演示如何在App中使用 Airprint进行打印.    1,打印机模拟器(Printer Simulator)下载 如果没有支持AirPrint的打印机也没关系,苹果提供了个虚拟打印机,地址:https://developer.apple.com/downloads (1)下载里面的 Hardware IO Tools 开发之Swift使用A

ios开发之Swift使用AVFoundation实现条形码扫描(附:拉近镜头改善读取)

1,条形码(一维码)的扫描读取 原来写过一篇文章,介绍如何使用摄像头扫描读取二维码:Swift - 二维码QRCode的读取(从图片读取 ,或通过摄像头扫描)要通过摄像头读取条形码,只需要将原来二维码读取代码中 metadataObjectTypes 做如下修改即可: self.output.metadataObjectTypes = [AVMetadataObjectTypeEAN13Code,         AVMetadataObjectTypeEAN8Code, AVMetadataO

ios开发之Swift闭包使用示例

什么是闭包? 闭包是指可以包含自由(未绑定到特定对象)变量的代码块:这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量). "闭包" 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域). 在Swift中,Swift的闭包跟OC中的Block很像,OC中的Block类似于匿名函数,闭包用来定义函数. 无论是OC中的Block还是Swift中的闭

ios开发之Swift UIPasteboard剪贴板的使用详解(复制、粘贴文字和图片)

UITextField.UITextView组件系统原生就支持文字的复制,但有时我们需要让其他的一些组件也能实现复制功能,比如点击复制UILabel上的文字.UIImageView中的图片.UITableView里单元格的内容.或者点击按钮把文字或图片自动复制到粘贴板中等等. 这些我们借助 UIPasteboard 就可以实现. 一,将内容写入到剪贴板中 1,复制字符串 UIPasteboard.generalPasteboard().string = "欢迎访问 hangge.com"

ios开发之Swift二维码QRCode的读取(从图片读取 ,或通过摄像头扫描)

1,直接读取图片中的二维码 使用 CIDetector 可以很方便的检测并读取二维码.下面是一个从 UIImage 中读取二维码的样例,我们要把图片上所有的二维码信息都打印出来. 开发之Swift二维码QRCode的读取(从图片读取 ,或通过摄像头扫描)-qrcode 读取二维码">    代码如下 复制代码 import UIKit   class ViewController: UIViewController {       override func viewDidLoad() {

ios开发之Swift自动优化照片调整善图像质量

Core Image能通过分析图片的各个属性,人脸的区域等进行自动优化图片.我们只需要调用autoAdjustmentFiltersWithOptions这个API方法获取各个自动增强滤镜来优化图片即可.不管是人物照片还是风景照均可增强效果. (以前另外还有个叫autoAdjustmentFilters的方法,现已废除.)   1,具体使用的滤镜如下: (1)CIRedEyeCorrection:修复因相机的闪光灯导致的各种红眼 (2)CIFaceBalance:调整肤色 (3)CIVibran

ios开发之Swift实现抠图,及图片合成功能的实现

大家肯定都用过PS进行抠图(扣图),而在Swift中,使用代码也可以实现抠图功能. 1,要把一个人物或物体从背景中抠出来,通常有两种办法: (1)使用CoreImage色域:适合纯色背景(或者背景色相对单一,色差不会太大),抠图精准   (2)使用openCv边缘检测:复杂背景情况也适用,默认抠图不够精确       2,下面使用第一种方案把下面的小猫抠出来,放置到雪地背景上.   开发之Swift实现抠图,及图片合成功能的实现-swift 实现分享功能">        3,如何使用Co

ios开发之Swift使用CIFilter生成二维码图片(QRCode)

CIFilter提供了各种各样的滤镜,其中CIQRCodeGenerator可以用来生成二维码.下面通过一个样例演示如何将字符串(链接也是字符串)生成二维码图片,同时支持在二维码中间放置个性化图标.   效果图如下: 开发之Swift使用CIFilter生成二维码图片(QRCode)-php qrcode生成二维码">    代码如下 复制代码 import UIKit   class ViewController: UIViewController {       override fu