Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Mirror(reflecting: self) too slow?

I am trying to make a dictionary with the properties of a class of mine.

class SomeClass() {
    var someString = "Hello, stackoverflow"
    var someInt = 42 // The answer to life, the universe and everything
    var someBool = true

    func objectToDict() -> [String: String] {
        var dict = [String: String]()
        let reflection = Mirror(reflecting: self)
        for child in reflection.children {
            if let key = child.label {
            dict[key] = child.value as? AnyObject
        }
        return dict
    }
}

but objectToDict() is very slow. Is there a way to speed this up, or may be another approach to add the property values to a Dictionary?

like image 898
user3352185 Avatar asked Sep 12 '25 20:09

user3352185


2 Answers

I do not agree with most other users. Using reflection results less code, which means less time to develop, maintain, and test your product. With a well written library like EVReflection you don't need to worry about things behind the scene too much.

However, if performance is going to be a concern, do NOT use reflection based approaches at all. I'd say it's never really a problem in front-end development for me, especially in iOS, but it cannot be ignored in back-end development.

To see how slow it can be, I ran some test in Xcode. I'll write a blog about it, but generally speaking, getting Mirror is not the worst part (plus it may be possible to catch property list in memory), so replacing it with objc runtime wouldn't change the situation too much. In the other hand, setValue(_, forKey) is surprisingly slow. Considering that in real life you also need to perform tasks like checking dynamicType and so on, using the dynamic approach surely will make it 100+ times slower, which won't be acceptable for server development.

- Looping 1,000,000 times for a class with 1 `Int` property
  - Getting mirror: 1.52
  - Looping throw mirror and set `child.value`: 3.3
  - Looping throw mirror and set `42`: 3.27
  - Setting value `42`: 0.05

Again, for iOS I'll keep using it to save my time. Hopefully end customers won't care about whether it's 0.005 seconds or 0.0005 seconds.

like image 153
superarts.org Avatar answered Sep 14 '25 10:09

superarts.org


Not only is that slow, it's also not a good idea: mirroring is for debug introspection only. You should instead construct the dictionary yourself. This ensures that you have the flexibility to store all the data in exactly the right way, and also decouples your Swift property names from the keys of the dictionary you're generating.

class SomeClass {
    var someString = "Hello, stackoverflow"
    var someInt = 42 // The answer to life, the universe and everything
    var someBool = true

    func objectToDict() -> [String: AnyObject] {
        return ["someString": someString, "someInt": someInt, "someBool": someBool]
    }
}
like image 24
andyvn22 Avatar answered Sep 14 '25 11:09

andyvn22