1、继承关系
NSTaggedPointerString(栈区) ---> NSString
__NSCFConstantString(数据常量区) ---> __NSCFString (堆区) --->NSMutableString --->NSString
__NSCFConstantString
字符串常量,是一种编译时常量,它的 retainCount 值很大,是 4294967295,对其进行 release 操作,retainCount 也不会产生任何变化。对象存储在字符串常量区。
__NSCFString
在运行时创建的一种 NSString 子类,他并不是一种字符串常量。所以和其他的对象一样在被创建时获得了 1 的引用计数。对象被存储在堆上。
NSTaggedPointerString
这种对象被直接存储在指针的内容中,可以当作一种伪对象。
用 copy 修饰的 NSString 如果在无意中被一个 NSMutableString 类型的变量赋值,原先的 NSString 会被 copy 一份用来存储 NSMutableString 的值,万一 NSMutableString 的值被修改,不会影响到 NSString 的值,这能体现 NSString 作为不可变类型的性质。 用 strong 修饰的 NSString 如果在无意中被一个 NSMutableString 类型的变量赋值, NSString 不会被拷贝,一旦 NSMutableString 的值被修改, NSString 的值也就发生了改变,这与 NSString 作为不可变类型相违背。
为什么NSString使用copy修饰也就可以理解了。使用copy修饰之后,即使属性拷贝来自可变字符串,也会被深拷贝成不可变字符串,也就是源字符串修改之后不会影响到属性字符串,增强了代码的健壮性。
当然如果 NSString 被一个 NSString 赋值, copy 的效果与 strong 的效果是一样的,直接改了就是。 以上的结论同样适用于 NSArray 和 NSDictionary 。
关于不可变字符串和数组的copy是浅拷贝也很好理解,既然数据源本身是不可变的,也就是具备安全性,那么系统默认浅拷贝其中数据,显然是合理的做法。
copy出来的字符串一定是不可变字符串,如果传入的是可变字符串,会发生深拷贝为不可变字符串,否则为浅拷贝。
mutablecopy,一定是深拷贝,拷贝出来的一定是可变字符串或者数组,即使传入的是不可变字符串或者数组。