funct7
funct7

Reputation: 3601

Objective-C copy attribute of property not working when using designated inits

Is this expected behavior?

For instance, with the class declared like so:

@interface XYZPerson : NSObject

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

+ (instancetype)personWithFirstName:(NSString *)firstName lastName:(NSString *)lastName birthday:(NSDate *)birthday;

@end

@implementation XYZPerson
+ (instancetype)personWithFirstName:(NSString *)firstName lastName:(NSString *)lastName birthday:(NSDate *)birthday {
    return [[self alloc] initWithFirstName:firstName lastName:lastName birthday:birthday];
}

- (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName birthday:(NSDate *)birthday {
    self = [super init];
    if (self) {
        _firstName = firstName;
        _lastName = lastName;
        _birthday = birthday;
    }
    return self;
}

- (instancetype)init {
    return [self initWithFirstName:@"John" lastName:@"Doe" birthday:[NSDate date]];
}

the getter doesn't copy in the following:

NSMutableString *name1 = [NSMutableString stringWithString:@"First"];
NSDate *birthday1 = [NSDate dateWithYear:1900 month:10 day:10];

XYZPerson *person = [XYZPerson personWithFirstName:name1 lastName:@"Last" birthday:birthday1];

NSMutableString *n1 = (NSMutableString *)person.firstName;
[n1 appendString:@"ttt"];

NSLog(@"%@", person.firstName);   // Prints Firstttt

However, this throws an exception (This is the expected behavior, since the following code calls appendString on immutable NSString:

XYZPerson *person = [XYZPerson new];
person.firstName = name1;
person.lastName = @"Last";
person.birthday = birthday1;

NSMutableString *n1 = (NSMutableString *)person.firstName;
[n1 appendString:@"ttt"];

NSLog(@"%@", person.firstName);

Am I missing something in my code?

Update Additionally, if this is the expected behavior, not an anomaly, should we not use factory methods for properties that should be copied?

Upvotes: 1

Views: 353

Answers (2)

funct7
funct7

Reputation: 3601

Obviously I missed to read the following part:

If you need to set a copy property’s instance variable directly, for example in an initializer method, don’t forget to set a copy of the original object:

Upvotes: 1

gnasher729
gnasher729

Reputation: 52602

You are assigning to the backing variables. This does not use the accessor methods, and no copying will happen.

And assigning an NSString* to an NSMutableString* doesn't make it mutable. If the compiler doesn't give you a warning for that then change your settings in Xcode.

Upvotes: 2

Related Questions