2

What's the best practice for implementing NSCopying across a two class inheritance hierarchy? I would like to have a deep copy of both Square and Shape's properties on a copy.

The 3 questions I have:

  1. Do both the parent and child class need to declare that they're implementing NSCopying or it adequate to only declare it on the base class?
  2. I've seen some people use [instance copy] instead of [instance copyWithZone:] Is this just a preference or is it more correct to use: copyWithZone?
  3. When copying arrays, is it correct to do: newObj.list = [[NSArray alloc] initWithArray:self.list copyItems:YES];

Here's what I have:

@interface Shape : NSObject <NSCopying>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSNumber *sides;
@property (nonatomic, strong) NSArray *list;
@end

@implementation Shape 

- (id)copyWithZone:(NSZone *)zone {
    Shape *shape = [[[self class] allocWithZone:zone] init];

    // Is it correct to use copyWithZone: instead of copy? eg: [self.name copy]
    shape->_name = [self.name copyWithZone:zone];
    shape->_sides = [self.sides copyWithZone:zone];
    shape->_list = [[NSArray alloc] initWithArray:self.list copyItems:YES];

    return shape;
}
@end

// Does this class also need to declare <NSCopying>?
@interface Square : Shape 
@property (nonatomic, strong) NSString *color;
@property (nonatomic, strong) NSArray *corners;
@end

@implementation Square
- (id)copyWithZone:(NSZone *)zone {
    // Will this ensure a deep copy of the inherited properties?
    Square *square = [[[self class] allocWithZone:zone] init];

    square->_color = [self.color copyWithZone:zone];    
    square->_corners = [[NSArray alloc] initWithArray:self.corners copyItems:YES];

    return square;
}
@end
Willam Hill
  • 1,572
  • 1
  • 17
  • 28
  • possible duplicate of [Implementing NSCopying in Subclass of Subclass](http://stackoverflow.com/questions/4472904/implementing-nscopying-in-subclass-of-subclass) – jscs Jan 12 '14 at 03:19
  • Sort of. I did see that question but it didn't answer all of the questions I had. – Willam Hill Jan 12 '14 at 03:20
  • Please be more specific about your questions, then. What exactly don't you understand? What exactly isn't answered there? – jscs Jan 12 '14 at 03:23

1 Answers1

0

Do both the parent and child class need to declare that they're implementing NSCopying or it adequate to only declare it on the base class?

It is a matter of style. I generally do not declare NSCopying again, but it may provide a little clarity if it's not obvious.

I've seen some people use [instance copy] instead of [instance copyWithZone:] Is this just a preference or is it more correct to use: copyWithZone?

It is fine to call copy. Zones haven't been used in a very long time (I don't believe that OS X ever used them.) You should override copyWithZone:, however.

When copying arrays, is it correct to do: newObj.list = [[NSArray alloc] initWithArray:self.list copyItems:YES];

Yes, this is necessary, but is not sufficient if the objects in the array do not implement a deep copy in their copyWithZone:. Note that this calls copy, not mutableCopy. So if you have an array of mutable arrays, you will wind up with an array of arrays. If you need to maintain mutability, you have to call mutableCopy yourself.

You have made one mistake, however:

// Will this ensure a deep copy of the inherited properties?
Square *square = [[[self class] allocWithZone:zone] init];

No, you need to call:

Square *square = [super copy];
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • If a copy is done as mentioned, should a subsequent isEqual check on the existing and cloned objects return true? Would I need to implement a custom isEqual? – Willam Hill Jan 13 '14 at 17:29
  • You would need to implement a custom `-isEqual:` and a custom `-hash`. The default `-isEqual` validates that the objects are actually the same object. You must always implement `-hash` if you implement `-isEqual:`. – Rob Napier Jan 13 '14 at 18:45