Swift-Reflection
5830 ワード
前言
Javaに詳しい読者は反射(Reflection)を知っているかもしれません.これは、実行時にタイプの動作を検出、アクセス、または変更する特性です.一般的な静的言語タイプの構造やメソッドの呼び出しなどはコンパイル時に決定する必要があり,開発者ができることはifやswitchなどの制御フローだけを用いてどのような設定や呼び出しを行うかを決定することが多い.反射特性は、実行時にいくつかの条件で呼び出しの方法をリアルタイムで決定したり、あるタイプに属性や方法を動的に設定したりする機会を与えることができ、非常に柔軟で強力な言語特性です.
Objective-Cでは、Objective-Cの動作時が一般的な反射よりも柔軟で強力であるため、「反射」という言葉はあまり言及されません.文字列によってクラスやselectorを生成し、さらにオブジェクトや呼び出し方法を生成するなど、反射の具体的な表現に慣れている読者も多いかもしれません.一方,SwiftではObjective-Cの実行時の部分を捨てても,純粋なSwiftの範疇には反射に関するいくつかの内容が存在するが,相対的に機能が弱い.
『Swifter:100個のSwift開発必須Tip』より抜粋
需要取得クラスの属性リスト 属性付与 Swift反射の実現方式 Mirror OC runtime
方法一:Mirror
インプリメンテーションモード
属性のタイプの取得
属性に値を割り当てる
特長単純(Swiftのすべてのタイプが_Reflectableを実現) はタイプの属性を取得できず、インスタンスの属性 のみを取得できる.は、 を取得できない.
方式2:OC runtime
インプリメンテーション方式(部分コード)
属性のタイプの取得
属性に値を割り当てる
特長は、クラスまたはインスタンス に作用する強力な機能を備えています.は面倒で、Objective-Cの基礎 が必要です.初期化されていない非参照タイプ属性を取得できません(値タイプは初期化する必要があります!) が作用するオブジェクトは、NSObject から継承する必要があります.
使用法(ユニットテスト添付)
属性リストの取得
静的属性に値を割り当てる(KVC)
インスタンス属性に値を割り当てる
Javaに詳しい読者は反射(Reflection)を知っているかもしれません.これは、実行時にタイプの動作を検出、アクセス、または変更する特性です.一般的な静的言語タイプの構造やメソッドの呼び出しなどはコンパイル時に決定する必要があり,開発者ができることはifやswitchなどの制御フローだけを用いてどのような設定や呼び出しを行うかを決定することが多い.反射特性は、実行時にいくつかの条件で呼び出しの方法をリアルタイムで決定したり、あるタイプに属性や方法を動的に設定したりする機会を与えることができ、非常に柔軟で強力な言語特性です.
Objective-Cでは、Objective-Cの動作時が一般的な反射よりも柔軟で強力であるため、「反射」という言葉はあまり言及されません.文字列によってクラスやselectorを生成し、さらにオブジェクトや呼び出し方法を生成するなど、反射の具体的な表現に慣れている読者も多いかもしれません.一方,SwiftではObjective-Cの実行時の部分を捨てても,純粋なSwiftの範疇には反射に関するいくつかの内容が存在するが,相対的に機能が弱い.
『Swifter:100個のSwift開発必須Tip』より抜粋
需要
方法一:Mirror
インプリメンテーションモード
属性のタイプの取得
func getTypeOfProperty (_ name: String) -> Any.Type {
// :self ( ), ,
var type: Mirror = Mirror(reflecting: self)
for child in type.children {
if child.label! == name {
return type(of: child.value)
}
}
while let parent = type.superclassMirror {
for child in parent.children {
if child.label! == name {
return type(of: child.value)
}
}
type = parent
}
return NSNull.Type.self
}
属性に値を割り当てる
func setObjectParams(obj: NSObject, paramsDic:[String:Any]?) {
if let paramsDic = paramsDic {
for (key,value) in paramsDic {
let type = obj.getTypeOfProperty(key)
if type == NSNull.Type.self {
print("[\(obj)] [\(key)] ")
}else if …… {
// ……
}else {
obj.setValue(value, forKey: key)
}
}
}
}
特長
get
またはset
と書かれたメソッドの属性方式2:OC runtime
インプリメンテーション方式(部分コード)
属性のタイプの取得
///
/// - : , , , !
/// - :https://github.com/Sajjon/SwiftReflection
///
/// - parameter clazz:
///
/// - returns: & .
open class func propertyList(clazz: NSObject.Type) -> [[String: Any]]? {
var count: UInt32 = 0
let list = class_copyPropertyList(clazz, &count)
var resultList = [[String: Any]]()
for i in 0..
属性に値を割り当てる
///
///
/// - parameter paramsDict:
/// - parameter obj:
/// - parameter complete:
open class func setParams(_ paramsDict:[String:Any]?, for obj: NSObject, complete: (()->()) = {}) {
if let paramsDict = paramsDict {
let clazz: NSObject.Type = type(of: obj)
let list = propertyList(clazz: clazz) ?? []
var filteredList = [[String: Any]]()
let _ = paramsDict.map({ dict in
let tmp = list.filter({ $0.keys.contains(dict.key)}).first ?? [:]
filteredList.append(tmp)
})
print("================= =================")
for (key, value) in paramsDict {
// key
let value = "\(value)"
let type = getType(key: key, typeDictList: filteredList)
if InnerConst.BOOL == type {
let toValue = value.toBool() ?? false
obj.setValue(toValue, forKey: key)
} else if …… {
// ……
} else if InnerConst.NULL == type {
print("[\(obj)] [\(key)] ")
}
}
print("================= =================")
complete()
}
}
特長
使用法(ユニットテスト添付)
属性リストの取得
func testGetPropertyList() {
if let list = SwiftReflectionTool.propertyList(clazz: Book.self) {
for dict in list {
for (value, type) in dict {
print("\(value) : \(type)")
}
}
} else {
print(" !")
}
}
静的属性に値を割り当てる(KVC)
func testSetParams4StaticProperty() {
print("============== ==============")
print(" :count = \(Book.value(forKey: InnerConst.CountKey) ?? "")")
Book.setValue(2, forKey: InnerConst.CountKey)
print(" :count = \(Book.value(forKey: InnerConst.CountKey) ?? "")")
}
インスタンス属性に値を割り当てる
func testSetParams4InstanceProperty() {
print("============== ==============")
let paramsDict = [
"title": "XXX ",
"author": "cy",
"numberOfPages": 250,
"released": "20170707",
"isSaled": true
] as [String : Any]
let book = Book(title: "", author: "", numberOfPages: 0, released: Date(), isSaled: false)
print(" :")
printProperties(obj: book)
SwiftReflectionTool.setParams(paramsDict, for: book) {
print(" ")
}
print(" :")
printProperties(obj: book)
}
//
private func printProperties(obj: NSObject) {
if let list = SwiftReflectionTool.propertyList(clazz: type(of: obj)) {
for dict in list {
for (value, _) in dict {
print("\(value) : \(obj.value(forKey: value) ?? "")")
}
}
} else {
print(" !")
}
}