第一种情况: 使用 copy 修饰
// 代码片段1
// Person.h
@interface Person : NSObject
@property (nonatomic, copy) NSString *lastName;
@end
// Person.m
@implementation Person
- (instancetype)init {
self = [super init];
if (self) {
_lastName = @"name";
}
return self;
}
@end
// main.m
int main(int argc, const char * argv[]) {
Person *p1 = [[Person alloc] init];
NSLog(@"lastname = %@, lastname address = %p", p1.lastName, p1.lastName);
NSMutableString *newLastName = [[NSMutableString alloc] initWithString:@"newname"];
NSLog(@"newLastName = %@, newLastName address = %p", newLastName, newLastName);
p1.lastName = newLastName;
NSLog(@"lastname = %@, lastname address = %p", p1.lastName, p1.lastName);
return 0;
}
以上代码执行后的结果如下:
lastname = name, lastname address = 0x100001078
newLastName = newname, newLastName address = 0x1003031e0
lastname = newname, lastname address = 0x100303720
从以上打印的结果可以看到,第一次打印的 lastname address和第二次打印的 lastname address 结果并不相同,同时 newLastName address 和第二次打印的 lastname address 也不相同,说明执行 p1.lastName = newLastName 之后 p1.lastName 指向了一块全新的内存空间,这就是 copy 的作用:重新开辟一块内存空间存放 newLastName 的值。
改变一: 修改 main 方法中的代码,在 return 0 之前添加以下代码
[newLastName appendString:@"abc"];
NSLog(@"lastname = %@, lastname address = %p", p1.lastName, p1.lastName);
newLastName 的值变成了 newnameabc,但是 p1.lastName 的值没有任何变化。这很简单,根据 copy 的作用 p1.lastName 和 newLastName 指向完全不同的地址,对 newLastName 做的改变自然不会反映在 p1.lastName 上。
第二种情况: 使用 strong 修饰
将代码:
@property (nonatomic, copy) NSString *lastName;
修改为:
@property (nonatomic, strong) NSString *lastName;
执行代码片段1之后的结果如下:
lastname = name, lastname address = 0x100001068
newLastName = newname, newLastName address = 0x100202e00
lastname = newname, lastname address = 0x100202e00
从以上结果中发现第一次打印的 lastname address 和第二次打印的 lastname address 指向不同的内存,但是第二次打印的 lastname address 和 newLastName address 相同,说明,与 copy 不同的是,strong 并没有开辟一块新的内存空间,而是直接将 lastname 指向了 newLastName。
改变一: 修改 main 方法中的代码,在 return 0 之前添加以下代码
[newLastName appendString:@"abc"];
NSLog(@"newLastName = %@, newLastName address = %p", newLastName, newLastName);
NSLog(@"lastname = %@, lastname address = %p", p1.lastName, p1.lastName);
打印结果如下:
newLastName = newnameabc, newLastName address = 0x100202e00
lastname = newnameabc, lastname address = 0x100202e00
因为 newLastName 和 p1.lastname 指向同一个内存,对 newLastName 的改变也就改变了 p1.lastname。但是 lastname 属性是不可变的 NSString 类型,而在这里却发生了改变。
另外
如果有以下代码:
@property (nonatomic, copy) NSMutableString *mString;
如果在未来给 mString 重新赋了一个新值,则会产生一个不可变的副本,此时想在 mString 上调用 NSMutableString 的相关方法是不行的。
结论
用 copy 修饰的 NSString 如果在无意中被一个 NSMutableString 类型的变量赋值,原先的 NSString 会被 copy 一份用来存储 NSMutableString 的值,万一 NSMutableString 的值被修改,不会影响到 NSString 的值,这能体现 NSString 作为不可变类型的性质。
用 strong 修饰的 NSString 如果在无意中被一个 NSMutableString 类型的变量赋值, NSString 不会被拷贝,一旦 NSMutableString 的值被修改,NSString 的值也就发生了改变,这与 NSString 作为不可变类型相违背。
当然如果 NSString 被一个 NSString 赋值,copy 的效果与 strong 的效果是一样的,直接改了就是。
以上的结论同样适用于 NSArray 和 NSDictionary。