1. 程式人生 > >【Swift】反射(Reflection)的介紹

【Swift】反射(Reflection)的介紹

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

樣例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 = [“

[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)”)
}

樣例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 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 = [“[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訪問屬性值
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 = [“[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)”)
}
(2)通過key設定對應的屬性值
//建立一個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)

相關推薦

Swift反射Reflection介紹

1,反射(Reflection) 對於C#、Java開發人員來說,肯定都對反射這個概念相當熟悉。所謂反射就是可以動態獲取型別、成員資訊,同時在執行時(而非編譯時)可以動態呼叫任意方法、屬性等行為的特性。 以Java上的兩個知名框架(hibernate和spr

Swift - 反射Reflection介紹與使用樣例附KVC介紹

comment 人員 BE display java pri ex18 pla 是否 1,反射(Reflection) 對於C#、Java開發人員來說,肯定都對反射這個概念相當熟悉。所謂反射就是可以動態獲取類型、成員信息,同時在運行時(而非編譯時)可以動態調用任意方法、屬性

dsPIC33EBootloaderMicrochip的Hex檔案結構介紹

市面上大多數微控制器的Hex檔案都是基於Intel Hex,而dsPIC33E也不例外,dsPIC33E支援的格式為Intel HEX32(INHX32)。 hex檔案以ascii形式,按照行來記錄資料 每一行從:開始,每至少2個字元表示一組16進位制資料,格式為 :BBAAAATTHH

dsPIC33EBootloaderBootloader的介紹與Flash結構

對於嵌入式開發而言,Bootloader幾乎與作業系統同等重要,它可以讓我們擺脫MCU官方工具,定製自己的燒錄工具,不僅提高產品辨識度,同時也大大減少了對外引腳數量(例如相容通訊的Uart或CAN等,而不需要另外接JTAG)。 要開發Bootloader,相對於普通程式,是有一定難度的,這其

轉載AzkabanAzkaban的基礎介紹

known thml solo inpu 簡單的 表格 嚴格 cad 描述 一、為什麽需要工作流調度器 1、一個完整的數據分析系統通常都是由大量任務單元組成: shell 腳本程序,java 程序,mapreduce 程序、hive 腳本等 2、各任務單元之間存在時間先後及

java簡介

編碼 http ... 設計 適合 不能 高度 代碼格式 操作系統 應用:web後端開發、android-app開發、大數據應用開發 學習:java會過時,但程序設計的思想不會過時 特點:1、面向對象,跨平臺,語法比c++簡單     2、以字節碼的形式運行在虛擬機上   

JavaDateUtil2

繼承 ava sim pla bool private throw ons tar import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat;

USACO15FEB審查黃金Censoring (Gold)

clu amp del lease sed better n) truct mos 題目描述 Farmer John has purchased a subscription to Good Hooveskeeping magazine for his cows, so

C# 反射Reflection的用處分析

roi 文章 acc contain fin oid bject 打印 normal 亂侃 作為一名新手,一直沒有勇氣去寫一篇分享。原因有很多:諸如:自己水平有限、語言表達不準確、寫出的東西沒有一點技術點被人嘲笑。今天在公司聽了內部員工的一個分享,其中最重要的一點是:

C# 反射Reflection

message console 反射 .html sys getmethod png source 文件 什麽是反射 發射是 .net framework 提供的一個幫助類庫,用於讀取和使用元數據。 用到的類:System.Reflection,System.Type。

BZOJ2940條紋博弈論

span char 一個 處理 || long long 簡單 sizeof .com 【BZOJ2940】條紋(博弈論) 題面 BZOJ 神TM權限題。 題解 我們把題目看成取石子的話,題目就變成了這樣: 有一堆\(m\)個石頭,每次可以取走\(c,z,n\)個,每次取完

學習reactjs——使用npm創建react項目並整合elementUI

web -s from 頁面 rain tle export build head 在實習的過程中了解了react,所以打算使用react搭建一個屬於自己的頁面,如有問題請教正,謝謝。 Github:https://github.com/yclxt/react-elemen

CF1068BLCM數學

div amp pri stream color can con scan namespace 題意:給定b,求lcm(a,b)/a有幾種不同的取值 b<=1e10 思路:只有a取b的因子時答案兩兩不同 1 #include<cstdio> 2 #i

HDOJ5510BazingaKMP

題意:給定n個由小寫字母組成的字串,第i個字串為a[i],求最大的j滿足存在1<=i<j,a[i]不是a[j]的子串,無解輸出-1 T<=50,n<=500,len[i]<=2000 思路:隊友寫的,抱大腿 判斷某個串是否是另一個串的子串可以使用KMP 有一個優化:若a[

Java基礎——反射Reflection

一、什麼是反射 在執行狀態中,對於任意一個類,都能夠獲取到這個類的所有屬性和方法,對於任意一個物件,都能夠呼叫它的任意一個方法和屬性(包括私有的方法和屬性),這種動態獲取的資訊以及動態呼叫物件的方法的功能就稱為java語言的反射機制。通俗點講,通過反射,該類對我們來說是完全透明的,想

BZOJ3351RegionsIOI2009-分塊+vector

測試地址:Regions 題目大意: 給定一棵 n n n個點的有根樹,每個點有顏色,

BZOJ3131淘金SDOI2013-數位DP+優先佇列

測試地址:淘金 做法: 本題需要用到數位DP+優先佇列。 令 F ( x

BZOJ1432函式ZJOI2009-思維

測試地址:函式 做法: 本題需要用到思維。 如果在 x x x座標為負無窮時,把函式從下到上編號為

Java反射reflection特點

*.class檔案介紹 學習Java的初學者都知道Java中存在JVM來包裝java語言使得java在各種機器上都能很好的執行。一個*.java的檔案首先編譯成*.class檔案,*.class檔案是JVM能夠識別的檔案,最後*.class檔案在JVM下編譯成機器可以識別的二進位制檔案。

C++向量vector 基本使用方法及注意事項

介紹: 向量(Vector)是一個封裝了動態大小陣列的順序容器(Sequence Container)。跟任意其它型別容器一樣,它能夠存放各種型別的物件。可以簡單的認為,向量是一個能夠存放任意型別的動態陣列。 特點: 1.順序序列 順序容器中的元素按照嚴格的線性順序排序。可以通過元素