我一直在寻找从结构创建字典的最有效方法。经过小规模的研究,我找到了通过初始化所有属性来转换它的简单方法:
func toDictionary() -> [String : AnyObject] {
let dictionary: [String: AnyObject] = ["firstProperty" : sth, "secondProperty" : "sth2"]
return dictionary
}
但是等等..我每次都要在我的结构中进行初始化吗?他们可能有一堆财产。它让我思考。如果我能以某种方式循环播放属性,我该怎么办?是的,可以使用Mirror
反射。经过一段时间的尝试我已经得到它 - 而不是上面的功能,我已经编写了实现一个功能的协议。
protocol Mirrorable {
func toDictionary() -> [String : AnyObject]
}
然后在我的结构中我可以简单地使用:
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
}
}
好奇心不让我停止思考它。哪种方式会更有效率?
答案 0 :(得分:5)
直接转换速度更快,但由于大多数情况下您不必将1.000.000+结构转换为字典,因此我使用协议扩展。
我创建了一个Mac cmd行应用来测试时间,正如预期的那样,直接转换更快。 这很明显,因为编译器可以对其进行优化,因为代码本身很简单。使用反射时,你会创建一堆额外的结构和变量,也会增加一些开销。
即使直接转换更快,我认为在大多数情况下使用协议扩展方法都很好,因为它很容易在您的代码库中采用。你必须记住的一件事是你的代码使用反射不考虑嵌套对象,这会使方法更慢,如果你使用递归会产生更大的开销。
以下是将1.000.000结构编码为字典的3次执行的结果:
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)
}