yer*_*rpy 1 reflection dictionary swift
我一直在寻找从结构创建字典的最有效方法。经过细致的研究,我发现了一种通过初始化所有属性来转换它的简便方法:
func toDictionary() -> [String : AnyObject] {
let dictionary: [String: AnyObject] = ["firstProperty" : sth, "secondProperty" : "sth2"]
return dictionary
}
Run Code Online (Sandbox Code Playgroud)
但是,等等。我是否必须在结构中每次都初始化它?他们可能有很多财产。.这让我思考。如果我可以通过类的循环获得属性怎么办。是的,可以使用Mirror反射。经过一段时间的尝试,我明白了—而不是上面的功能,我编写了实现一个功能的协议。
protocol Mirrorable {
func toDictionary() -> [String : AnyObject]
}
Run Code Online (Sandbox Code Playgroud)
然后在我的结构中,我可以简单地使用:
extension MyStructure/MyClass : Mirrorable {
func toDictionary() -> [String : AnyObject] {
let reflection = Mirror(reflecting: self).children
var dictionary = [String : AnyObject]()
for (label, value) in reflection {
dictionary[label!] = value as AnyObject
}
return dictionary
}
}
Run Code Online (Sandbox Code Playgroud)
好奇心并没有让我停止思考。哪种方法更有效?
直接转换速度更快,但是由于大多数情况下您不必将1.000.000+结构转换为字典,因此我将使用协议扩展。
我创建了一个Mac cmd line应用程序来测试时间,并且正如预期的那样,直接转换更快。这很明显,因为编译器可以优化它,并且代码本身很简单。使用反射时,您会创建大量额外的结构和变量,还增加了一些开销。
尽管直接转换更快,但我认为在大多数实际情况下,使用协议扩展方法会很好,因为它很容易在您的代码库中采用。您必须记住的一件事是,使用反射的代码未考虑嵌套对象,这会使该方法变得更慢,并且如果您使用递归将产生更大的开销。
以下是3次执行的结果,这些执行将1.000.000结构编码为字典:
Apple LLVM 8.1-代码生成
Swift编译器-代码生成:
使用S1(直接转换)执行1000000次的时间:0.569061994552612
使用S2(结构扩展+协议)执行1000000次的时间:7.68360501527786
使用S3(协议扩展)执行1000000次的时间:7.71803396940231
使用S1(直接转换)执行1000000次的时间:0.500779032707214
使用S2(结构扩展+协议)执行1000000次的时间:7.58478999137878
使用S3(协议扩展)执行1000000次的时间:7.73368299007416
使用S1(直接转换)执行1000000次的时间:0.492152035236359
使用S2(结构扩展+协议)执行1000000次的时间:7.81585901975632
使用S3(协议扩展)执行1000000次的时间:7.41855001449585
Apple LLVM 8.1-代码生成
Swift编译器-代码生成:
使用S1(直接转换)执行1000000次的时间:2.92627400159836
使用S2(结构扩展+协议)执行1000000次的时间:9.25952398777008
使用S3(协议扩展)执行1000000次的时间:9.19355899095535
使用S1(直接转换)执行1000000次的时间:2.9830749630928
使用S2(结构扩展+协议)执行1000000次的时间:9.06750500202179
使用S3(协议扩展)执行1000000次的时间:8.77240401506424
使用S1(直接转换)执行1000000次的时间:2.81389397382736
使用S2(结构扩展+协议)执行1000000次的时间:8.84287703037262
使用S3(协议扩展)执行1000000次的时间:9.08754301071167
Apple LLVM 8.1-代码生成
Swift编译器-代码生成:
使用S1(直接转换)执行1000000次的时间:0.533200979232788
使用S2(结构扩展+协议)执行1000000次的时间:8.15365797281265
使用S3(协议扩展)执行1000000次的时间:7.80043601989746
使用S1(直接转换)执行1000000次的时间:0.509769976139069
使用S2(结构扩展+协议)执行1000000次的时间:7.76911997795105
使用S3(协议扩展)执行1000000次的时间:8.00845402479172
使用S1(直接转换)执行1000000次的时间:0.532546997070312
使用S2(结构扩展+协议)执行1000000次的时间:7.99552202224731
使用S3(协议扩展)执行1000000次的时间:7.86273497343063
Apple LLVM 8.1-代码生成
Swift编译器-代码生成:
使用S1(直接转换)执行1000000次的时间:2.90398299694061
使用S2(结构扩展+协议)执行1000000次的时间:9.62662398815155
使用S3(协议扩展)执行1000000次的时间:9.55038601160049
使用S1(直接转换)执行1000000次的时间:2.98312002420425
使用S2(结构扩展+协议)执行1000000次的时间:9.62088203430176
使用S3(协议扩展)执行1000000次的时间:8.82720899581909
使用S1(直接转换)执行1000000次的时间:2.77569997310638
使用S2(结构扩展+协议)执行1000000次的时间:8.83749902248383
使用S3(协议扩展)执行1000000次的时间:8.76373296976089
import Foundation
// Direct conversion to dictionary
struct S1 {
var a: Int
var b: Int
var c: Int
func toDictionary() -> [String : AnyObject] {
let dictionary: [String: AnyObject] = [
"a":a as AnyObject,
"b":b as AnyObject,
"c":c as AnyObject
]
return dictionary
}
}
// Conversion using struct extension + protocol
protocol Mirrorable1 {
func toDictionary() -> [String : AnyObject]
}
struct S2 {
var a: Int
var b: Int
var c: Int
}
extension S2: Mirrorable1 {
func toDictionary() -> [String : AnyObject] {
let reflection = Mirror(reflecting: self).children
var dictionary = [String : AnyObject]()
for (label, value) in reflection {
dictionary[label!] = value as AnyObject
}
return dictionary
}
}
// Conversion using protocol extension
protocol Mirrorable2 {
func toDictionary() -> [String : AnyObject]
}
extension Mirrorable2 {
func toDictionary() -> [String : AnyObject] {
let reflection = Mirror(reflecting: self).children
var dictionary = [String : AnyObject]()
for (label, value) in reflection {
dictionary[label!] = value as AnyObject
}
return dictionary
}
}
struct S3: Mirrorable2 {
var a: Int
var b: Int
var c: Int
}
let listOfExecutions = [1_000_000, 1_000_000, 1_000_000]
for executions in listOfExecutions {
// S1
var start = CFAbsoluteTimeGetCurrent()
for i in 0..<executions {
S1(a: 0, b: 1, c: 2).toDictionary()
}
print("Time for \(executions) executions with S1(direct conversion):")
print(CFAbsoluteTimeGetCurrent() - start)
// S2
start = CFAbsoluteTimeGetCurrent()
for i in 0..<executions {
S2(a: 0, b: 1, c: 2).toDictionary()
}
print("Time for \(executions) executions with S2(struct extension + protocol):")
print(CFAbsoluteTimeGetCurrent() - start)
// S3
start = CFAbsoluteTimeGetCurrent()
for i in 0..<executions {
S3(a: 0, b: 1, c: 2).toDictionary()
}
print("Time for \(executions) executions with S3(protocol extension):")
print(CFAbsoluteTimeGetCurrent() - start)
}
Run Code Online (Sandbox Code Playgroud)