Imagine that you:
-
have a property of non-mutable class (
NSString
,NSArray
,NSDictionary
etc) which hascopy
modifier:@property (copy, nonatomic) NSString *name;
-
It's possible to assign no it any mutable subclass instance (
NSMutableString
,NSMutableArray
,NSMutableDictionary
etc) -
You have to pay attention while implementing custom constructors.
See this example:
The property is declared as copy
User.m
@interface User : NSObject
@property (copy, nonatomic) NSString *name;
- (instancetype)initWithName:(NSString *)name;
@end
The problem is in the constructor
User.m
- (instancetype)initWithName:(NSString *)name {
if (self = [super init]) {
// Just assigns. Setter won't be called!
_name = name;
// Correct:
// _name = [name copy];
}
return self;
}
NSString *stringName = @"John";
NSMutableString *mutableStringName = [NSMutableString stringWithString:@"John"];
User *userWithNonmutable = [[User alloc] initWithName:stringName];
User *userWithMutable = [[User alloc] initWithName:mutableStringName];
NSLog(@"Nonmutable variable: %@; Pointer: %p", stringName, stringName);
NSLog(@"Mutable variable : %@; Pointer: %p", mutableStringName, mutableStringName);
NSLog(@"");
NSLog(@"Nonmutable before : %@; Pointer: %p", userWithNonmutable.name, userWithNonmutable.name);
NSLog(@"Mutable before : %@; Pointer: %p", userWithMutable.name, userWithMutable.name);
NSLog(@"");
NSString *newName = @"Steeve";
NSLog(@"Change each var from \"%@\" to \"%@\"\n", stringName, newName);
stringName = newName;
// I don't want "mutableStringName" to change the pointer
[mutableStringName replaceOccurrencesOfString:mutableStringName
withString:newName
options:NSCaseInsensitiveSearch
range:NSMakeRange(0, mutableStringName.length)];
NSLog(@"");
NSLog(@"Nonmutable after : %@; Pointer: %p", userWithNonmutable.name, userWithNonmutable.name);
NSLog(@"Mutable after : %@; Pointer: %p // <-- Value's changed!", userWithMutable.name, userWithMutable.name);