1

An array exists (named visits) which stores instances of Visit.

Scenario: A user click a button, enters a number, and that number is stored as a property on a newly created visit as a member of visits.

This is my code:

[visits addObject: [visits lastObject]];
Visit * lastVisit = [visits lastObject];
lastVisit.examDate = [NSLocale currentLocale];
lastVisit.edss_numeric = 5.5;

On inspection, I expected to have added a new visit to the end of my visits array (which it did) but the original last visit was then updated with the information I wanted to be set for the true last visit. In short, the last two visits are now identical and the originally copied visit changed (when it should not have).

What fundamentals of objective C am I not understanding and how can I fix this to achieve my desired results?

1
  • Curious: Why is a property named examDate defined with a type of NSLocale? Date and locale are two completely different things. Commented May 5, 2016 at 22:51

2 Answers 2

3

[visits lastObject] returns a reference pointing to an object whose type is Visit. What you are doing is, adding that reference to the array again. Because of that, if you update the object through one of them, second reference will get affected since they both point to same object.

Does the Visit class implement NSCopying protocol? If it does, you can create a copy of the last object and add it to the array so you'll have two references pointing to two different objects:

@interface Visit: NSObject <NSCopying>

@property (nonatomic, strong) NSLocale *examDate;
@property (nonatomic, assign) CGFloat edss_numeric;

@end

--

@implementation Visit

- (id)copyWithZone:(NSZone *)zone {
  Visit *copy = [[self class] allocWithZone:zone];
  if (copy) {
    copy.examDate = [self.examDate copyWithZone:zone];
    copy.edss_numeric = self.edss_numeric;
  }
  return copy;
}

@end

Then, you can add the copy of the last object to the array as follows:

Visit *lastVisit = [visits.lastObject copy];
lastVisit.examDate = [NSLocale currentLocale];
lastVisit.edss_numeric = 5.5;

[visits addObject:lastVisit];
Sign up to request clarification or add additional context in comments.

2 Comments

The NSCopying protocol is indeed supported.
Then you should call copy on the last object and update the properties of the copy instead.
0

When you do this

[visits addObject: [visits lastObject]];

you add a reference to the last Visit object to your NSArray again. Since it's only a reference, not a new object, any modifications to the "new last" will be reflected in the "old last" as well: it is the same object.

To fix this problem, insert a copy of last instead:

[visits addObject: [[Visit alloc] initWithOriginal:[visits lastObject]];

Add initWithOriginal: initializer to your Visit class, and copy the data as necessary into a new object.

1 Comment

Thank you. I appreciate you pushing me in the right direction.

Your Answer

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