问题引入:
NSString都存储在堆区吗?会不会存在栈区,或者数据区呢?
NSString用copy修饰还是strong修饰?NSString调用copy和mutableCopy会创建一个新的内存空间吗?NSMutableString用copy修饰会导致什么样的后果?
一.各类型字符串的关系和存储方式
NSString和NSMutableString相信我们平时都用过n遍了,但NSString真的都是一个存储在堆区的对象吗?如果在不同区,对它们进行copy操作,内存地址又会是什么样呢?
几个需要注意的点:
内存地址由低到高分别为:程序区-->数据区-->堆区-->栈区
其中堆区分配内存从低往高分配,栈区分配内存从高往低分配
1.继承关系:
NSTaggedPointerString(栈区) ---> NSString
__NSCFConstantString(数据常量区) ---> __NSCFString (堆区) --->NSMutableString --->NSString
2.对于NSStringFromClass()方法,字符串较短的class,系统会对其进行比较特殊的内存管理,NSObject字符串比较短,直接存储在栈区,类型为NSTaggedPointerString,不论你NSStringFromClass多少次,得到的都是同一个内存地址的string;但对于较长的class,则为__NSCFString类型,而NSCFString存储在堆区,每次NSStringFromClass都会得到不同内存地址的string
3.__NSCFConstantString类型的字符串,存储在数据区,即使当前控制器被dealloc释放了,存在于这个控制器的该字符串所在内存仍然不会被销毁.通过快捷方式创建的字符串,无论字符串多长或多短,都是__NSCFConstantString类型,存储在数据区.
下面是实际代码测试的结果,对象内存地址和指针内存地址都作了相应注释:
NSString *str1 = @"abcdeefghijk";//该种方式无论字符串多长,都是__NSCFConstantString类型,存储在数据区,0x0000000104b2c400
NSString *strDigital = @"999";//即使很短,也是(__NSCFConstantString *)类型, 0x00000001092b1420,存储在数据区
NSString *str1Copy = [str1 copy];//__NSCFConstantString,NSString类型的str1进行copy是浅拷贝,并不会拷贝一份新的内存地址,0x0000000104b2c400,内存地址和str1相同
NSMutableString *str1MutableCopy = [str1 mutableCopy];//__NSCFString,NSString类型str1进行mutableCopy后是深拷贝,0x0000600000d7d590
NSMutableString *str1MutaCopyCopy = [str1MutableCopy copy];//__NSCFString,mutableString类型的str1MutableCopy进行mutableCopy后是深拷贝,0x0000600000373980
[str1MutableCopy appendString:@"12"];
[str1MutaCopyCopy appendString:@"34"];//本行代码崩溃,原因是mutableString进行copy虽然是深拷贝,但返回的是不可变类型,只有NSMutableString才有appendString方法,__NSCFString没有appendString方法;虽然用NSMutableString接收,但str1MutaCopyCopy的类型还是由实际运行过程决定
NSString * cfStringLongClass = NSStringFromClass([ViewController class]);//较长类情况下,该方法获得的字符串是类型__NSCFString存储在堆区,0x00006000003739a0
NSString *taggedStrShortClass = NSStringFromClass([NSObject class]);//较短类情况下,该方法获得的字符串是NSTaggedPointerString类型,存储在栈区,0x86b1d57ef6188519
NSString *taggedStrShortClassCopy = [taggedStrShortClass copy];//(NSTaggedPointerString *) $0 = 0xac71e37414f16209 @"NSObject" 内存地址不会变,浅拷贝,值也相同
NSString *taggedStrShortClassMutaCopy = [taggedStrShortClass mutableCopy];//(__NSCFString *) $2 = 0x00006000036f4030 @"NSObject",内存地址变化,深拷贝一份至堆区,值相同,
NSObject *obj = [[NSObject alloc]init];//对象存储在堆区,0x0000600000c61160
//总结:stringWithFormat方式,最终字符串的类型由字符串长度决定,少于10个字符类型为NSTaggedPointerString,否则为__NS