Search code examples
iosarraysswiftdeep-copyshallow-copy

Make a shallow copy of collection classes (Array, Dictionary) in swift, not a deep copy.


There seems to be a lot of confusion and different opinions on this out there, I want to know, is that possible in swift to make a shallow copy of an object and not a deep copy.

I checked in JAVA - http://www.jusfortechies.com/java/core-java/deepcopy_and_shallowcopy.php, It's clearly explained the difference between shallow copy and deep copy with example, but I didn't got kind of example in swift.

I tried initWithArray:copyItems: to check what difference does it make when I'm changing the Boolean flag of copyItems, but none of the difference I see. I supposed to have difference of shallow or deep copy by changing the copyItems flag, but I was wrong it creates a deep copy always.

Please check my below code, I cloned the array object arrayObject1 to arrayObject2 using initWithArray:copyItems: by setting copyItems: to true. I changed the arrayObject2 0th string object to new string object and arrayObject2 0th object changed, but arrayObject1 0th object didn't changed. whereas if I'm copying it by assigning copyItems: to false, then also I'm having the same result.

So how to achieve a shallow copy and if it's not by initWithArray:copyItems: then what copyItems: flag making impact on result.

func createAnArrayUsingArrayCopyItems(){

        let name = "albort"
        let arrayObject1 = NSArray.init(objects: name, 15)
        let arrayObject2 = NSMutableArray.init(array: arrayObject1 as [AnyObject], copyItems: true)
        arrayObject2[0] = "john"
        print(arrayObject1)
        print(arrayObject2)

    }  

Output ->
enter image description here


Solution

  • It happens because name is a Swift String instance. String is struct, thus it's a value type. That is because it's always copied by value. arrayObject1 as [AnyObject] is a conversion to swift Array (a struct too) with String objects within.

    So it's not trivial to get a shallow copy using such structures like Array and String in Swift.

    I can only come up with an idea of boxing struct instances into a class wrapper:

    class StringBox : CustomStringConvertible, NSCopying {
      var string: String
    
      init(str: String) {
        string = str
      }
    
      var description: String {
        return "\(string)"
      }
    
      @objc func copyWithZone(zone: NSZone) -> AnyObject {
        return StringBox(str: string)
      }
    }
    
    func createAnArrayUsingArrayCopyItems(){
      let name = StringBox(str: "albort")
      let arrayObject1 = NSArray.init(objects: name, 15)
      let arrayObject2 = NSMutableArray.init(array: arrayObject1 as [AnyObject], copyItems: false)
      (arrayObject2[0] as! StringBox).string = "john"
      print(arrayObject1[0])
      print(arrayObject2[0])
    }
    
    createAnArrayUsingArrayCopyItems()
    

    It gives me a following output:

    john
    john