问: 为什么要用 copy
修饰 NSString
?
带着问题我们进行如下讨论: 测试代码
1、不可变字符串copy
NSString *str = @"string";
NSLog(@"%p",str);
NSString *strCopy1 = [str copy];
NSLog(@"%p",strCopy1);
NSMutableString *strCopy2 = [str copy];
NSLog(@"%p",strCopy2);
NSString *strCopy3 = [str copy];
NSLog(@"%p",strCopy3);
NSMutableString *strCopy4 = [str copy];
NSLog(@"%p",strCopy4);
//如果取消下面的注释,则crash,strCopy2实质还是不可变字符串
// [strCopy2 appendString:@"1"];
控制台输出如下
2016-12-22 14:25:11.636 CopyAndStrong[16067:400558] 0x10adab098
2016-12-22 14:25:11.636 CopyAndStrong[16067:400558] 0x10adab098
2016-12-22 14:25:11.637 CopyAndStrong[16067:400558] 0x10adab098
2016-12-22 14:25:11.637 CopyAndStrong[16067:400558] 0x10adab098
2016-12-22 14:25:11.637 CopyAndStrong[16067:400558] 0x10adab098
NSString的copy只是相当于“强引用” ,也就是浅拷贝。
下图是该字符串的isa指针类型,根据名称就可以知道0x10adab098
在常量区,存放字符串量,而不论你对一个字符串常量怎么copy,他依然还是静静地在常量区做一个字符串常量
2、不可变字符串mutableCopy
NSString *str = @"string";
NSLog(@"%p",str);
NSString *strMutableCopy1 = [str mutableCopy];
NSLog(@"%p",strMutableCopy1);
NSMutableString *strMutableCopy2 = [str mutableCopy];
NSLog(@"%p",strMutableCopy2);
NSString *strMutableCopy3 = [str mutableCopy];
NSLog(@"%p",strMutableCopy3);
NSMutableString *strMutableCopy4 = [str mutableCopy];
NSLog(@"%p",strMutableCopy4);
控制台输出如下
2016-12-22 14:36:20.605 CopyAndStrong[16067:400558] 0x10adab098
2016-12-22 14:36:20.605 CopyAndStrong[16067:400558] 0x60800007db80
2016-12-22 14:36:20.605 CopyAndStrong[16067:400558] 0x600000261e40
2016-12-22 14:36:20.606 CopyAndStrong[16067:400558] 0x608000260300
2016-12-22 14:36:20.606 CopyAndStrong[16067:400558] 0x60800007db40
每一个mutableCopy的字符串,地址都不同,而且他们的样式和 0x10adab098
明显不同,这里我执行如下代码
UIView *view = [UIView new];
NSLog(@"%p",view); // 输出 `0x7fc4ec503e50`
发现堆区对象的地址和mutableCopy
的字符串得到的字符串地址极为相似,得出结论mutableCopy之后的字符串在堆区,而他们的类型其实都是NSMutableString
,参考如下截图
3、可变字符串的copy
NSString *str = @"string";
NSLog(@"%p",str);
NSMutableString *mutableStr = [str mutableCopy];
NSLog(@"%p",mutableStr);
NSString *MutableStrCopy1 = [mutableStr copy];
NSLog(@"%p",MutableStrCopy1);
NSMutableString *MutableStrCopy2 = [mutableStr copy];
NSLog(@"%p",MutableStrCopy2);
NSString *MutableStrCopy3 = [mutableStr copy];
NSLog(@"%p",MutableStrCopy3);
NSMutableString *MutableStrCopy4 = [mutableStr copy];
NSLog(@"%p",MutableStrCopy4);
// [MutableStrCopy2 appendString:@"1"];//取消注释就会crash,copy之后实际是不可变字符串
控制台输出如下
2016-12-22 14:54:26.257 CopyAndStrong[16151:410074] 0x106181098
2016-12-22 14:54:26.257 CopyAndStrong[16151:410074] 0x608000078240
2016-12-22 14:54:26.258 CopyAndStrong[16151:410074] 0xa00676e697274736
2016-12-22 14:54:26.258 CopyAndStrong[16151:410074] 0xa00676e697274736
2016-12-22 14:54:26.258 CopyAndStrong[16151:410074] 0xa00676e697274736
2016-12-22 14:54:26.258 CopyAndStrong[16151:410074] 0xa00676e697274736
四次copy,结果都是同一个地址,而且这里打印出来的地址有点奇怪,我在控制台看到如下描述:
查了资料发现一个叫做
Tagged Pointer
的东西,这里不做解释。。。
4、可变字符串的mutableCopy
NSString *str = @"string";
NSLog(@"%p",str);
NSMutableString *mutableStr = [str mutableCopy];
NSLog(@"%p",mutableStr);
NSString *MutableStrMutableCopy1 = [mutableStr mutableCopy];
NSLog(@"%p",MutableStrMutableCopy1);
NSMutableString *MutableStrMutableCopy2 = [mutableStr mutableCopy];
NSLog(@"%p",MutableStrMutableCopy2);
NSString *MutableStrMutableCopy3 = [mutableStr mutableCopy];
NSLog(@"%p",MutableStrMutableCopy3);
NSMutableString *MutableStrMutableCopy4 = [mutableStr mutableCopy];
NSLog(@"%p",MutableStrMutableCopy4);
控制台输出如下
2016-12-22 15:13:45.732 CopyAndStrong[16356:430316] 0x10e0fa098
2016-12-22 15:13:45.732 CopyAndStrong[16356:430316] 0x60000006e240
2016-12-22 15:13:45.733 CopyAndStrong[16356:430316] 0x600000071ac0
2016-12-22 15:13:45.733 CopyAndStrong[16356:430316] 0x618000072740
2016-12-22 15:13:45.733 CopyAndStrong[16356:430316] 0x610000071dc0
2016-12-22 15:13:45.733 CopyAndStrong[16356:430316] 0x608000070dc0
类似不可变字符串的mutableCopy
总结:
- copy产生不可变字符串,mutableCopy产生可变字符串;
- 只要mutablecopy就会开辟空间, copy可变字符串才会开辟空间;
答: 为什么要用 copy
修饰 NSString
?
如果用 NSString
强引用一个 NSMutableString
,他们实际都是指向同一个NSMutableString
, 而一旦NSMutableString
的值改变,那么所谓的NSString
也随之改变