Andrea
Andrea

Reputation: 795

Trouble with NSString and copy attribute

I'm learning Objective C with the book "Programming with Objective C", but I'm stuck with the exercises 3 on page 66.

I have the following properties:

@property (copy, readonly) NSString *lastName;
@property (copy, readonly) NSString *firstName;

the following methods:

+ (id) personWithLastName:(NSString *)aLastName andFirstName:(NSString *)aFirstName {
    return [[self alloc] initWithLastName:aLastName andFirstName:aFirstName;
}

- (id) initWithLastName:(NSString *)aLastName andFirstName:(NSString *)aFirstName {
    self = [super init];
    if (self) {
        _lastName = aLastName;
        _firstName = aFirstName;
    }
    return self;
}

- (void) sayHello {
    NSString *greeting = [NSString stringWithFormat:@"Hello, %@ %@!", [self firstName], [self lastName]];
    [self saySomething:greeting];
}

and the following code in the main:

NSMutableString *firstName = [NSMutableString stringWithString:@"Steve"];
NSString *lastName = @"Jobs";

XYZPerson* firstPerson = [XYZPerson personWithLastName:lastName andFirstName:firstName];
[firstPerson sayHello];

which correctly print "Hello, Steve Jobs!".

Later, I added the following lines:

[firstName setString:@"John"];
[firstPerson sayHello];

which edit the property firstName in the object firstPerson, and print "Hello, John Jobs!". However, firstName have the copy attribute, so why this happen?

Upvotes: 0

Views: 90

Answers (2)

Alladinian
Alladinian

Reputation: 35616

Well let's break this down...

This property says that we want only an accessor to be generated (the readonly part) plus we take ownership of the object via copy upon assignment (which in this case is never gonna happen because of the readonly)

@property (copy, readonly) NSString *lastName;

So a better form would be (unless you're interested in redeclaration of the property as readwrite in a class extension, like in this answer):

@property (readonly) NSString *lastName;

and now we copy inside our init method before assignment to the backing ivars:

- (id) initWithLastName:(NSString *)aLastName andFirstName:(NSString *)aFirstName {
    self = [super init];
    if (self) {
        _lastName = [aLastName copy];
        _firstName = [aFirstName copy];
    }
    return self;
}

and of course the same applies to your other property also.

Upvotes: 1

Ben Pious
Ben Pious

Reputation: 4805

The firstName and Lastname you are using in your main method are not the properties you declared, but instead new instance variables. To access the properties you want you can use _firstName to use the ivar or self.firstName to use the property's setter and getter methods.

EDIT: Disregard the above. Because you are using the ivar directly instead of calling the accessor method, the copy is not being made -- you have to call copy yourself.

Upvotes: 0

Related Questions