Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 将结构属性转换为字典的更有效方法_Swift_Dictionary_Reflection - Fatal编程技术网

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-整个模块优化
使用S1执行1000000次的时间(直接转换): 0.569061994552612

使用S2(结构扩展+协议)执行1000000次的时间: 7.68360501527786

使用S3执行1000000次的时间(协议扩展): 7.718033969431

使用S1执行1000000次的时间(直接转换): 0.500779032707214

使用S2(结构扩展+协议)执行1000000次的时间: 7.58478999137878

使用S3执行1000000次的时间(协议扩展): 7.7336829900716

使用S1执行1000000次的时间(直接转换): 0.49215203359

使用S2(结构扩展+协议)执行1000000次的时间: 7.81585901975632

使用S3执行1000000次的时间(协议扩展): 7.41855001449585

生成设置
  • Apple LLVM 8.1-代码生成

    • 优化级别:-Ofast
  • Swift编译器-代码生成:

    • 优化级别:-ONONONE
使用S1执行1000000次的时间(直接转换): 2.92627400159836

使用S2(结构扩展+协议)执行1000000次的时间: 9.2595239877008

使用S3执行1000000次的时间(协议扩展): 9.19355899095535

使用S1执行1000000次的时间(直接转换): 2.9830749630928

使用S2(结构扩展+协议)执行1000000次的时间: 9.06750500202179

使用S3执行1000000次的时间(协议扩展): 8.77240401506424

使用S1执行1000000次的时间(直接转换): 2.81389397382736

使用S2(结构扩展+协议)执行1000000次的时间: 8.8428770307262

使用S3执行1000000次的时间(协议扩展): 9.08754301071167

生成设置
  • Apple LLVM 8.1-代码生成

    • 优化级别:-O0
  • Swift编译器-代码生成:

    • 优化级别:-O-整个模块优化
使用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.53254697070312

使用S2(结构扩展+协议)执行1000000次的时间: 7.99552202224731

使用S3执行1000000次的时间(协议扩展): 7.86273497343063

生成设置
  • Apple LLVM 8.1-代码生成

    • 优化级别:-O0
  • Swift编译器-代码生成:

    • 优化级别:-ONONONE
使用S1执行1000000次的时间(直接转换): 2.90398299694061

使用S2(结构扩展+协议)执行1000000次的时间: 9.62662398815155

使用S3执行1000000次的时间(协议扩展): 9.55038601160049

使用S1执行1000000次的时间(直接转换): 2.98312002420425

使用S2(结构扩展+协议)执行1000000次的时间: 9.6208803430176

使用S3执行1000000次的时间(协议扩展): 8.82720899581909

使用S1执行1000000次的时间(直接转换): 2.77569997310638

使用S2(结构扩展+协议)执行1000000次的时间: 8.837499022483

使用S3执行1000000次的时间(协议扩展): 8.76373296976089

代码: <代码>导入基础 //直接转换为字典 结构S1{ 变量a:Int 变量b:
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)
}