NSString 不同的初始化方式会产生三种不同的类型
1.产生的对象是 __NSCFConstantString
2.产生的对象是 __NSCFString
3.产生的对象是 NSTaggedPointerString
三种类型分别是什么,分别是在什么情况下产生的,分别处于内存的那个区域?
__NSCFConstantString
字符串常量,是一种编译时常量,它的 retainCount 值很大,是 4294967295,在控制台打印出的数值则是 18446744073709551615==2^64-1,测试证明,即便对其进行 release 操作,retainCount 也不会产生任何变化。是创建之后便是放不掉的对象。相同内容的 __NSCFConstantString 对象的地址相同,也就是说常量字符串对象是一种单例。
这种对象一般通过字面值 @"..."、CFSTR("...") 或者 stringWithString: 方法(需要说明的是,这个方法在 iOS6 SDK 中已经被称为redundant,使用这个方法会产生一条编译器警告。这个方法等同于字面值创建的方法)产生。
这种对象存储在字符串常量区。
__NSCFString
和 __NSCFConstantString 不同, __NSCFString 对象是在运行时创建的一种 NSString 子类,他并不是一种字符串常量。所以和其他的对象一样在被创建时获得了 1 的引用计数。
通过 NSString 的 stringWithFormat 等方法创建的 NSString 对象一般都是这种类型。
这种对象被存储在堆上。
NSTaggedPointerString
理解这个类型,需要明白什么是标签指针,这是苹果在 64 位环境下对 NSString,NSNumber 等对象做的一些优化。简单来讲可以理解为把指针指向的内容直接放在了指针变量的内存地址中,因为在 64 位环境下指针变量的大小达到了 8 位足以容纳一些长度较小的内容。于是使用了标签指针这种方式来优化数据的存储方式。从他的引用计数可以看出,这货也是一个释放不掉的单例常量对象。在运行时根据实际情况创建。
对于 NSString 对象来讲,当非字面值常量的数字,英文字母字符串的长度小于等于 9 的时候会自动成为 NSTaggedPointerString 类型,如果有中文或其他特殊符号(可能是非 ASCII 字符)存在的话则会直接成为 )__NSCFString 类型。
这种对象被直接存储在指针的内容中,可以当作一种伪对象。
深复制,浅复制
//***对于不可变非集合类型 copy 浅拷贝 mutableCopy 深拷贝
NSString * a = @"abc";//__NSCFConstantString
NSString * b = [a copy];//__NSCFConstantString
NSString * c = [a mutableCopy];//__NSCFString
NSLog(@"a ==%p,b ===%p,c==%p",a,b,c);//a ==0x103fc3068,b ===0x103fc3068,c==0x600002c962b0 指针拷贝
//***对于不可变非集合类型 copy 浅拷贝 mutableCopy 深拷贝
//对于可变的非集合类型,copy mutableCopy 均为深拷贝
NSMutableString * mutableString111 = [[NSMutableString alloc]initWithString:@"mutable不是的"];//__NSCFString
NSMutableString * mutableString = [[NSMutableString alloc]initWithString:@"mutable"];//__NSCFString
NSMutableString * string1 = [NSMutableString stringWithString:@"abc"];//__NSCFString
NSMutableString * copy = [mutableString copy];//NSTaggedPointerString
NSMutableString * mutableCopy = mutableString.mutableCopy;
NSLog(@"mutableString==%p,copy===%p,mutableCopy===%p",mutableString,copy,mutableCopy);
//mutableString==0x600002d1e400,copy===0xf24b6de84b26e70b,mutableCopy===0x600002d1e250 内存拷贝
//对于可变的非集合类型,copy mutableCopy 均为深拷贝
对于不可变容器,copy 浅复制 返回不可变 mutableCopy 深复制 返回可变对象
NSArray * arr = @[@"ad",@"cd"];//__NSArrayl
NSArray * copyArr = [arr copy];//__NSArrayl
NSArray * mutableCopyArr = [arr mutableCopy];//__NSArrayM
NSLog(@"arr == %p,copyArr==%p,mutableCopyArr==%p",arr,copyArr,mutableCopyArr);
// arr == 0x6000018fc5c0,copyArr==0x6000018fc5c0,mutableCopyArr==0x6000016f71e0
//对于不可变容器,copy 浅复制 返回不可变 mutableCopy 深复制 返回可变对象
对于可变的容器,copy mutableCopy 都是深复制
NSMutableArray* mutableArr =[[NSMutableArray alloc]initWithArray:arr];//__NSArrayM
NSMutableArray * copyMutableArr = mutableArr.copy;//__NSArrayl
NSMutableArray * mutableCopyMutableArr = mutableArr.mutableCopy;//__NSArrayM
NSLog(@"mutableArr == %p,copyMutableArr==%p,mutableCopyMutableArr==%p",mutableArr,copyMutableArr,mutableCopyMutableArr);
// mutableArr == 0x6000016ea640,copyMutableArr==0x6000018f0ae0,mutableCopyMutableArr==0x6000016ea490
// 对于可变的容器,copy mutableCopy 都是深复制
容器内有可变对象时,copy(浅复制) mutableCopy(深复制) 只进行一层复制 对于容器内的元素是浅复制
//容器内有不可变对象
// 1.创建一个不可变数组,数组内元素为可变字符串。
NSMutableString *red = [NSMutableString stringWithString:@"Red"];
NSMutableString *green = [NSMutableString stringWithString:@"Green"];
NSMutableString *blue = [NSMutableString stringWithString:@"Blue"];
NSArray *myArray1 = [NSArray arrayWithObjects:red, green, blue, nil];
// 2.进行浅复制。
NSArray *myArray2 = [myArray1 copy];
NSMutableArray *myMutableArray3 = [myArray1 mutableCopy];
NSArray *myArray4 = [[NSArray alloc] initWithArray:myArray1 copyItems:NO];
// 3.修改myArray2的第一个元素。
NSMutableString *tempString = myArray2.firstObject;
[tempString appendString:@"Color"];
// 4.输出四个数组内存地址及四个数组内容。
NSLog(@"Memory location of \n myArray1 = %p, \n myArray2 %p, \n myMutableArray3 %p, \n myArray4 %p",myArray1, myArray2, myMutableArray3, myArray4);
NSLog(@"Contents of \n myArray1 %@, \n myArray2 %@, \n myMutableArray3 %@, \n myArray4 %@",myArray1, myArray2, myMutableArray3, myArray4);
// 可以看到myArray1和myArray2数组内存地址相同,myMutableArray3和myArray4与其它数组内存地址各不相同。这是因为mutableCopy的对象会被分配新的内存,alloc会为对象分配新的内存空间。
// 观察数组内元素,发现修改myArray2数组内第一个元素,四个数组第一个元素都发生了改变,所以这里只进行了浅复制。
No1:可变对象的copy和mutableCopy方法都是深拷贝(区别完全深拷贝与单层深拷贝) 。
No2:不可变对象的copy方法是浅拷贝,mutableCopy方法是深拷贝。
No3:copy方法返回的对象都是不可变对象。
https://www.skyfly.xyz/2015/11/08/iOS/NSString的内存管理/
https://www.jianshu.com/p/f268e99afea4
https://www.jianshu.com/p/783498dd467b
网友评论