Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

copyWithZone setting instance variables?

Tags:

objective-c

Is the copyWithZone (See Below) correct, particularly the bit where I use the setters to populate the instance variables of the new object?

@interface Planet : NSObject <NSCopying>
{
    NSString *name;
    NSString *type;
    NSNumber *mass;
    int index;
}
@property(copy) NSString *name;
@property(copy) NSString *type;
@property(retain) NSNumber *mass;
@property(assign) int index;
-(void)display;
@end

-(id) copyWithZone: (NSZone *) zone {
    Planet *newPlanet = [[Planet allocWithZone:zone] init];
    NSLog(@"_copy: %@", [newPlanet self]);
    [newPlanet setName:name];
    [newPlanet setType:type];
    [newPlanet setMass:mass];
    [newPlanet setIndex:index];
    return(newPlanet);
}

EDIT_001:

Is this a better way?

-(id) copyWithZone: (NSZone *) zone {
    Planet *newPlanet = [[[self class] allocWithZone:zone] init];
    [newPlanet setName:[self name]];
    [newPlanet setType:[self type]];
    [newPlanet setMass:[self mass]];
    [newPlanet setIndex:[self index]];
    return(newPlanet);
}

many thanks

gary

like image 206
fuzzygoat Avatar asked Feb 04 '23 07:02

fuzzygoat


2 Answers

(Assuming deep copy is what you want) for the copy we want to make, use copyWithZone: for object instance variables and simply set primitive instance variables using =.

- (id)copyWithZone:(NSZone *)zone
{
    MyClass *copy = [[MyClass alloc] init];

    // deep copying object properties
    copy.objectPropertyOne = [[self.objectPropertyOne copyWithZone:zone] autorelease];
    copy.objectPropertyTwo = [[self.objectPropertyTwo copyWithZone:zone] autorelease];
                  ...
    copy.objectPropertyLast = [[self.objectPropertyLast copyWithZone:zone] autorelease];

    // deep copying primitive properties
    copy.primitivePropertyOne = self.primitivePropertyOne
    copy.primitivePropertyTwo = self.primitivePropertyTwo
                  ...
    copy.primitivePropertyLast = self.primitivePropertyLast

    // deep copying object properties that are of type MyClass
    copy.myClassPropertyOne = self.myClassPropertyOne
    copy.myClassPropertyTwo = self.myClassPropertyTwo
                  ...
    copy.myClassPropertyLast = self.myClassPropertyLast


    return copy;
}

But notice how properties of the same class as self and copy must be set without copyWithZone:. Otherwise, these objects will call this copyWithZone again, and will try to set their myClassProperties using copyWithZone as well. This triggers an unwanted infinite loop. (Also, you could call allocWithZone: instead of alloc: but I'm pretty sure alloc: calls allocWithZone: anyway)

There are some cases where using = to deep copy object properties of the same class might not be the thing you want to do, but in ALL CASES (as far as I'm aware) deepcopying object properties of the same class with copyWithZone: or anything that calls copyWithZone: will result in an infinite loop.

like image 96
Pedro Cattori Avatar answered Feb 13 '23 07:02

Pedro Cattori


Whether it's an unwanted copy or not is for you to decide. The reason to synthesize accessors with the copy qualifier is to be sure of the ownership of those objects.

Keep in mind though, that immutable objects like an NSNumber or an NSString won't actually duplicate their storage when they're sent a -copy message, they'll just increase their retain counts.

like image 35
NSResponder Avatar answered Feb 13 '23 06:02

NSResponder