Swift - 反射(Reflection)的介紹與使用樣例(附KVC介紹)
阿新 • • 發佈:2018-05-29
comment 人員 BE display java pri ex18 pla 是否 1,反射(Reflection)
在使用ObjC開發時很少強調其反射概念,因為ObjC的Runtime要比其他語言中的反射強大的多。在ObjC中可以很簡單的實現字符串和類型的轉換(NSClassFromString()),實現動態方法調用(performSelector: withObject:),動態賦值(KVC)等等。 3,Swift中的反射
在Swift中並不提倡使用Runtime,而是像其他語言一樣使用反射(Reflect)。當然,目前Swift中的反射還沒有其他語言中的反射功能強大,不僅遠不及OC的Runtime,離Java的反射也有一定的距離。
Swift的反射機制是基於一個叫 Mirror 的 struct 來實現的,其內部有如下屬性和方法:
4,Swift反射的使用樣例
樣例1:輸出實體對象的類名,屬性個數,以及所有屬性的屬性名和屬性值。 首先定義一個用戶類:
接著創建一個用戶對象,並通過反射獲取這個對象的信息:
控制臺輸出信息如下:
樣例2:通過屬性名(字符串)獲取對應的屬性值,並對值做類型判斷(包括是否為空)
首先為方便使用,這裏定義兩個方法。getValueByKey()是用來根據傳入的屬性名字符串來獲取對象中對應的屬性值。unwrap()是用來給可選類型拆包的(對於非可選類型則返回原值)
下面是實際測試樣例,同樣用上例的User對象做測試:
控制臺輸出信息如下:
附:通過KVC訪問屬性值
KVC是key-value coding的縮寫。它是一種間接訪問對象的機制。其本質是依據OC中Runtime的強大動態能力來實現的。在Swift中,只要類繼承NSObject即可使用KVC。(有一個叫KVO的,它又是基於KVC,大家有興趣的可以自行研究下。) KVC中:key的值就是屬性名稱的字符串,返回的value是任意類型,需要自己轉化為需要的類型。 (註意:正由於KVC是基於Objective-C的,所以其不支持可選類型(optional)的屬性,比如上例的 var age:Int?
因此用戶類做如下改造:)
KVC主要就是兩個方法:
(1)通過key獲得對應的屬性值
(2)通過key設置對應的屬性值
對於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 來實現的,其內部有如下屬性和方法:
1 2 3 4 |
let children: Children //對象的子節點。
displayStyle: Mirror . DisplayStyle ? //對象的展示風格
let subjectType: Any . Type //對象的類型
func superclassMirror() -> Mirror ? //對象父類的 mirror
|
4,Swift反射的使用樣例
樣例1:輸出實體對象的類名,屬性個數,以及所有屬性的屬性名和屬性值。 首先定義一個用戶類:
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 = 100
user1.emails = [ "[email protected]" , "[email protected]" ]
//將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
}
|
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 = 100
user1.emails = [ "[email protected]" , "[email protected]" ]
//通過屬性名字符串獲取對應的值
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是key-value coding的縮寫。它是一種間接訪問對象的機制。其本質是依據OC中Runtime的強大動態能力來實現的。在Swift中,只要類繼承NSObject即可使用KVC。(有一個叫KVO的,它又是基於KVC,大家有興趣的可以自行研究下。) KVC中:key的值就是屬性名稱的字符串,返回的value是任意類型,需要自己轉化為需要的類型。 (註意:正由於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 = 100
user1.emails = [ "[email protected]" , "[email protected]" ]
//使用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([ "[email protected]" , "[email protected]" ], 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介紹)