1.当源字符串是不可变的时候
对源头是NSString的字符串,无论是strong声明的变量还是copy声明的变量,当第二次源头的字符串重新指向其它的地方的时候,它还是指向原来的最初的那个位置
二者都是指针引用,也就是浅拷贝
浅拷贝 / 指针拷贝: 增加一个指针, 并且申请一个新的内存, 使新指针指向新内存
// 创建2种str
@property (nonatomic, strong) NSString *strongStr;
@property (nonatomic, copy) NSString *copyedStr;
// 初始化一个不可变str,赋值为abcd
NSString * tempStr = @"abcd";
self.strongStr = tempStr;
self.copyedStr = tempStr;
// 1、前者是字符串 “xxxx” 内存首地址
// 2、后者是指针str 内存首地址
NSLog(@"Str ----- %@ %p %p",Str,Str,&Str);
// 打印地址
tempStr ----- abcd 0x1024031b8 0x7ffeed7fcb08
strongStr ----- abcd 0x1024031b8 0x7ff288c05540
copyedStr ----- abcd 0x1024031b8 0x7ff288c05548
// 重新赋值为efg
tempStr = @"efg";
tempStr ----- efg 0x102403238 0x7ffeed7fcb08
strongStr ----- abcd 0x1024031b8 0x7ff288c05540
copyedStr ----- abcd 0x1024031b8 0x7ff288c05548
# strongStr 和 copyedStr 内容都还是abcd
# 无论是copy还是strong,都依然指向原来的地址,即为源字符串abcd指向的地址
# tempStr 改变不影响其他2个值的变化
2.当源字符串是可变的时候
对源头是NSMutableString的字符串,strong仅仅是指针引用,增加了引用计数器,这样源头改变的时候,用这种strong方式声明的变量(无论被赋值的变量是可变的还是不可变的 ,它也会跟着改变;而copy声明的变量,它不会跟着源头改变,是深拷贝
深拷贝 / 对象拷贝: 在有指针的情况下, 增加一个指针指向已经存在的内存 (OC中引用计数会+1)
NSMutableString * tempStr = [NSMutableString stringWithFormat:@"abcd"];
self.strongStr = tempStr;
self.copyedStr = tempStr;
// 打印地址
tempStr ----- abcd 0x60000024f570 0x7ffee9ecbb08
strongStr ----- abcd 0x60000024f570 0x7feced6069b0
copyedStr ----- abcd 0xa000000646362614 0x7feced6069b8
// 源字符串进行拼接
[tempStr appendString:@"efg"];
tempStr ----- abcdefg 0x60000024f570 0x7ffee9ecbb08
strongStr ----- abcdefg 0x60000024f570 0x7feced6069b0
copyedStr ----- abcd 0xa000000646362614 0x7feced6069b8
# strongStr 内容是abcdefg,copyedStr 内容还是abcd
# strongStr的类型实际上是NSMutableString,而不是NSString
# copy 对 源字符串进行了深拷贝,指向了新的地址,所以没有随之改变
结论:
我们声明NSString的时候最好使用copy,既然NSString是不可变的含义,我们就确保它不会发生改变
tips:即使copy修饰的属性是一个可变对象,发生了内存拷贝,但是其实拷贝出来的对象依然是不可变的
@property (nonatomic, copy) NSMutableString *copyedStr;
NSMutableString *tempName = [NSMutableString stringWithString:@"hello"];
self.copyedStr = tempName;
[self.copyedStr appendString:@" world"];
# 会崩溃,copyedStr 本质是不可变的
网友评论