3

I have an NSMutableArray that I'm passing into a tableViewController. The user will access and update data in the array. Add objects and remove objects.

To be able to get back to the state of the array before the user interacted with it, I thought I would make a copy of the array. That way if the user decided to cancel and not go ahead, I could just pass the copyArray back into the original array.

However, when I update some data on the original array, it get updated on the copy array as well.

And no, I didn't assign them to each other. I used the following code.

array2 = [array1 copy];

I have even tried the longwinded one.

NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:YES];

But if I set copyItems to YES, the app crashes with this error.

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SaleItem copyWithZone:]: unrecognized selector sent to instance 0xa21f3b0'

Jorgen
  • 465
  • 3
  • 10
  • 24
  • 1
    have you tried just [[NSMutableArray alloc] initWithArray:oldArray] ? – Nitin Alabur May 12 '14 at 21:58
  • 2
    `[NSArray copy]` creates a shallow copy of the array (i.e. it doesn't copy the contents of the array, merely makes new references to old objects. The 2nd form you use will attempt to copy the contents of the array using either `copy` or `copyWithZone` which are both part of the `NSCopying` protocol. You'll have to implement those for each content class if you want deep copies of arrays. – David Berry May 12 '14 at 22:00
  • 2
    Your SaleItem class doesn't know how to copy itself. You need to make it compliant with the `NSCopying` protocol. – ColdLogic May 12 '14 at 22:08

2 Answers2

8

You should look up the difference between a deep and a shallow copy of an array. In short, do you want just a copy of the data structures, or do you want copies of the items in the array too? (Should the original and the copy point to the same objects?)

To resolve this error:

  • Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SaleItem copyWithZone:]: unrecognized selector sent to instance 0xa21f3b0'

You also need to implement NSCopying in your SaleItem class.

Community
  • 1
  • 1
Aaron Brager
  • 65,323
  • 19
  • 161
  • 287
  • There was a subclass in SalesItems that also needed to have NSCopying implemented. Thanks to both @Isaac and Aaron as they put me in the right direction. – Jorgen May 13 '14 at 07:52
6

Making a "copy" of an NSArray (or initing a new array from the old one) will only give you a new array containing pointers to the same objects as the first array, not to copies of those objects. Based on an answer to another question on Stack Overflow, you can use:

NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:YES];

to get the first-level items copied (assuming they implement NSCopying), though that may or may not be sufficient for your purposes, depending on what those objects are. That question I linked to has more answers about making a "deep" copy of an NSArray.

Community
  • 1
  • 1
Isaac
  • 10,668
  • 5
  • 59
  • 68