12

I am trying to deep copy a Swift class instance. As copy and mutableCopy function are available only for NSObject class descendent, I am need to implement the copy function of my own for a Swift class object.

Here is what I did,

protocol Copying {
    init(original: Self)
}

extension Copying {
    func copy() -> Self {
        return Self.init(original: self)
    }
}

class A : Copying {
    var name : String? = nil
    var age : Int? = nil
    var address : String? = nil

    init(name : String) {
        self.name = name
    }

    required init(original: A) {
        //one way
        self.name = original.name
        self.age = original.age
        self.address = original.address

        //second way
        let originalReflect = Mirror(reflecting: original)
        let selfReflect = Mirror(reflecting: self)
         for (_, originalAttr) in originalReflect.children.enumerated() {
            for (_, attr) in selfReflect.children.enumerated() {
                if originalAttr.label == attr.label {
                    //now I know the value of property and its value as well in original
                    //but how will I set it to self?
                    //If A was NSObject I could have said
                    self.setValue(originalAttr.value, forKey: originalAttr.label!)


                }
            }
        }
    }
}

Finally this is how I access the copy

let aInstance = A(name: "Sandeep")
let aCopy = aInstance.copy()

The first method shown in required init(original: A) works absolutely fine, but not scalable. In my project I have base class with 50 odd property and atlas 50 more subclasses. Now I cant write the required init(original: A) for each subclass and add self.property = original.property that looks very much dumb way to solve it.

Second method shows the usage of Mirror to iterate through all the properties of object and but gets stuck as there is no way to set the value of self as self.setValue(for key) is not available for swift classes.

Now I cant change the class type to NSObject for this benefit nor can I convert it to struct.

Reference :

Copy Protocol idea from : deep copy for array of objects in swift

Mirror idea from : https://www.pluralsight.com/guides/microsoft-net/property-copying-between-two-objects-using-reflection

iterate over object class attributes in Swift

Any way to solve this? Suggestions would be really helpful.

Sandeep Bhandari
  • 19,999
  • 5
  • 45
  • 78
  • 1
    I think if you want to set the properties using a key path you have to mark them as `dynamic`. – Sweeper Aug 23 '17 at 08:37
  • @sweeper : Thank you for the information. I did read about dynamic. Sounds like a good solution though it means that access to the variables gonna use Objective-C run time (dynamic dispatch) but still not sure how can I access those variables using property name as setValue is still unavailable in swift3 – Sandeep Bhandari Aug 23 '17 at 09:08
  • @SandeepBhandari did you find a solution to copying structs without tons of boilerplate? – Petrus Theron Sep 05 '18 at 06:04
  • @petrus-theron : Its been quite a long time from when I posted this question, so I don't remember exactly the solution I opted for but I can be sure that I did not find a straight way to copy so I ended up with a solution 1 I believe I had some problem with Mirroring as well. solution 1 kinda solves the problem but am sure there exists much simpler and straight forward way but I dont know it yet :( – Sandeep Bhandari Sep 05 '18 at 08:14

0 Answers0