Swift 将结构属性转换为字典的更有效方法
我在寻找从结构创建字典的最有效方法。经过小规模的研究,我发现了一种简单的方法,可以通过初始化所有属性来转换它,如下所示:Swift 将结构属性转换为字典的更有效方法,swift,dictionary,reflection,Swift,Dictionary,Reflection,我在寻找从结构创建字典的最有效方法。经过小规模的研究,我发现了一种简单的方法,可以通过初始化所有属性来转换它,如下所示: func toDictionary() -> [String : AnyObject] { let dictionary: [String: AnyObject] = ["firstProperty" : sth, "secondProperty" : "sth2"] return dictionary } 但是等等。。我是否每次都必须在结构中初始化它
func toDictionary() -> [String : AnyObject] {
let dictionary: [String: AnyObject] = ["firstProperty" : sth, "secondProperty" : "sth2"]
return dictionary
}
但是等等。。我是否每次都必须在结构中初始化它?他们可能有一大笔财产。。它让我思考。如果我能以某种方式通过类的循环获得属性呢。是的,可以使用Mirror
reflection。经过一段时间的尝试,我得到了它——我编写了实现一个函数的协议,而不是上面的函数
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
}
}
好奇心并没有让我停止思考。哪种方式更有效 TLDR
直接转换速度更快,但由于大多数情况下不需要将1.000.000+结构转换为字典,所以我会使用协议扩展
长话短说 我创建了一个Mac cmd行应用程序来测试时间,正如预期的那样,直接转换速度更快。 这是显而易见的,因为编译器可以优化它,而且代码本身很简单。当使用反射时,您会创建一堆额外的结构和变量,同时也会增加一些开销 尽管直接转换速度更快,但我认为在大多数实际情况下,使用协议扩展方法会更好,因为它很容易在代码库中采用。您必须记住的一件事是,使用反射的代码没有考虑嵌套对象,这将使该方法更慢,而且如果使用递归,将产生更大的开销 以下是将1.000.000结构编码到字典的3次执行的结果: 生成设置
- Apple LLVM 8.1-代码生成
- 优化级别:-Ofast
- Swift编译器-代码生成:
- 优化级别:-O-整个模块优化
- Apple LLVM 8.1-代码生成
- 优化级别:-Ofast
- Swift编译器-代码生成:
- 优化级别:-ONONONE
- Apple LLVM 8.1-代码生成
- 优化级别:-O0
- Swift编译器-代码生成:
- 优化级别:-O-整个模块优化
- Apple LLVM 8.1-代码生成
- 优化级别:-O0
- Swift编译器-代码生成:
- 优化级别:-ONONONE
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)
}