2

First of all: I cannot use structs in my scenario. I know structs are "pass-by-value" by default. But i really need the "pass-by-reference" semantic of a class object in my case.

Like the title says, i am trying to deep copy an Array, which is holding optional objects of a custom class.

For the deep copy of a custom class object i implemented the following protocol:

protocol Copyable {
    init(instance: Self)
}

extension Copyable {
    func copy() -> Self {
        return Self.init(instance: self)
    }
}

Now i also have Arrays of custom class objects which need to be deep copied. To achieve this i wrote an extension for Array where Element is Copyable, which looks like this and is working:

extension Array where Element: Copyable {
    func clone() -> Array {
        var copiedArray = Array<Element>()
        for element in self {
            copiedArray.append(element.copy())
        }
        return copiedArray
    }
}

Let's say i have 2 custom classes. The first one is already conforming to Copyable and looks like this:

class MySimpleObject: Copyable {

    let myString: String

    init() {
        self.myString = ""
    }

    required init(instance: MySimpleObject) {
        self.myString = instance.myString
    }
}

Now my second custom class is holding two Arrays of MySimpleObject (1 Array where the element is MySimpleObject is non-optional and 1 where the element MySimpleObject is optional. This class looks like this:

class MyObject {

    var myArray = [MySimpleObject]()
    var myArrayWithOptionals = [MySimpleObject?]()
}

Now i want MyObject conform to Copyable and this is the part that confuses me. First i tried like this (but this gives me an error like shown in the comment:

class MyObject: Copyable {

    var myArray = [MySimpleObject]()
    var myArrayWithOptionals = [MySimpleObject?]()

    required init(instance: MyObject) {
        self.myArray = instance.myArray.clone()
        self.myArrayWithOptionals = instance.myArrayWithOptionals.clone()       // Type 'MySimpleObject?' does not conform to protocol 'Copyable'
    }
}

This error makes sense to me. Since MySimpleObject? is not equal MySimpleObject.

My Second try was then to write another extension to Array, but i am not sure how to do this in the correct way:

extension Array where Element == Optional<Copyable> {
    func cloneOptional() -> Array {
        var copiedArray = Array<Element>()
        for element in self {
            copiedArray.append(element?.copy())
        }
        return copiedArray
    }
}

MyObject looks like this then: But i also get an error (again shown in the comment)

class MyObject: Copyable {

    var myArray = [MySimpleObject]()
    var myArrayWithOptionals = [MySimpleObject?]()

    required init(instance: MyObject) {
        self.myArray = instance.myArray.clone()
        self.myArrayWithOptionals = instance.myArrayWithOptionals.cloneOptional()   // '[MySimpleObject?]' is not convertible to 'Array<Optional<Copyable>>'
    }
}

Can anyone hint me to the direction i need? How would we implement this in the correct way?

If you need more information in any way let me know in the comments.

Best Regards,

Teetz

1 Answer 1

2

It seems like you have bit of incorrect assumption for array extension of Optional Elements. You are calling copy on optional which you have not declared. Just make sure that Optional also conform to Copyable and it should work fine with clone on optional array.

extension Optional: Copyable where Wrapped: Copyable {
    init(instance: Optional<Wrapped>) {
        if let instance = instance {
            self = Optional(instance.copy())
        } else {
            self = nil
        }
    }
}

Altogether, your code would look something like this,

protocol Copyable {
    init(instance: Self)
}

extension Copyable {
    func copy() -> Self {
        return Self.init(instance: self)
    }
}

extension Optional: Copyable where Wrapped: Copyable {
    init(instance: Optional<Wrapped>) {
        if let instance = instance {
            self = Optional(instance.copy())
        } else {
            self = nil
        }
    }
}

extension Array where Element: Copyable {
    func clone() -> [Element] {
        var copiedArray = [Element]()
        for element in self {
            copiedArray.append(element.copy())
        }
        return copiedArray
    }
}

class MySimpleObject: Copyable {

    let myString: String

    init() {
        self.myString = ""
    }

    required init(instance: MySimpleObject) {
        self.myString = instance.myString
    }
}

class MyObject: Copyable {

    var myArray = [MySimpleObject]()
    var myArrayWithOptionals = [MySimpleObject?]()

    required init(instance: MyObject) {
        self.myArray = instance.myArray.clone()
        self.myArrayWithOptionals = instance.myArrayWithOptionals.clone()
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you @Sandeep. This is exactly what i needed. Working like a charm!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.