5

I have an array var arr = [myObject] I want to copy it to arr2 so that modifying object in the second the first remained as is (copy by value). How to make it?

AlexP
  • 449
  • 2
  • 9
  • 25
  • I believe this was answered here: https://stackoverflow.com/questions/30066274/swift-how-to-copy-an-array-that-contains-reference-types – Martin Muldoon Apr 07 '18 at 12:02
  • Your desired behaviour luckily is the default behaviour of Swift values types (e.g. Array). So whenever you assign an array to a new variable, you can modify it without affecting the original. – dr_barto Apr 07 '18 at 12:07
  • 1
    Not if the array contains reference types. – Martin Muldoon Apr 07 '18 at 12:08
  • A proper answer depends on what you have in the array. Does your array contain classes. structs, or enums? – rmaddy Apr 07 '18 at 16:45

3 Answers3

12

If the type within your array is an enum or a struct, no problem. You don't need to think about it:

var a = [1,2,3]
var b = a
b[1] = 3
b // [1, 3, 3]
a // [1, 2, 3]

If your array contains a class then you do need to think about how you copy objects, because by default you will be working with pointers to the same instances:

let ns = NSMutableArray()
var arr = [ns]
var arr2 = arr

arr2[0].add(2)
arr[0] // [2]

But where classes adopt the NSCopying protocol you can use copy() and mutableCopy() to make the necessary copies to resolve this:

var arr3 = arr.map(){$0.mutableCopy() as! NSMutableArray}
arr3[0].add(1)
arr3[0] // [2, 1]
arr[0] // [2]
arr2[0] // [2]

Where a class does not adopt the NSCopying protocol, you will need to extend or subclass, adding a copy(with:) method:

extension UIView: NSCopying {
    public func copy(with zone: NSZone? = nil) -> Any {
        return UIView(frame: self.frame)
    }
}

var aView = UIView(frame:CGRect(x: 0, y: 0, width: 100, height: 100))
var bView = aView.copy() as! UIView

aView.tag = 5
bView.tag // 0
aView.tag // 5

Note: The code example of copying a UIView is incredibly simplistic and assumes that a "copy" is simply a view the same size, whereas a copy in real use would be something more complex, most likely containing subviews, etc.

sketchyTech
  • 5,746
  • 1
  • 33
  • 56
4

actually the simplest way was to make: var arr2:[myObject] = Array(arr1)

P.S. thanks to all for suggestions

AlexP
  • 449
  • 2
  • 9
  • 25
0

You can do that by creating a computed property. And then lazy load it to declare as a class variable.

lazy var secondArray :[myObject] = { return firstArray }()

Now if you ever need second array, it will get you first array

Akshansh Thakur
  • 5,163
  • 2
  • 21
  • 38