Kiran Jasvanee
Kiran Jasvanee

Reputation: 6554

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

Upvotes: 0

Views: 990

Answers (2)

slashdot
slashdot

Reputation: 630

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

Upvotes: 1

Wain
Wain

Reputation: 119031

arrayObject2[0] = "john"

This is changing the item at position 0 in array 2 - not the contents of the string which already exists at that location of the array. For that to happen it would need to be an array of mutable strings.

Indeed if you create the array with mutable strings and then append to the string at position 0 in array 2 you will see the same string instance in array 1 is also updated (because it's the same instance).

Editing the array instance isn't the same as editing the instances in the array.

The copy is shallow if you ask it to be. Technically a shallow and deep copy are sometimes the same thing of the data types are immutable.

Upvotes: 1

Related Questions