参考博客
iOS - 老生常谈内存管理(五):Tagged Pointer
问题发现:
NSString *firstString = @"helloworld";
NSString *secondString = [NSString stringWithFormat:@"helloworld"];
NSString *thirdString = @"hello";
NSString *fourthSting = [NSString stringWithFormat:@"hello"];
NSLog(@"%p %@\n%p %@\n%p %@\n%p %@\n",firstString,[firstString class],secondString,[secondString class],thirdString,[thirdString class],fourthSting,[fourthSting class]);
创建四个字符串 一、三直接赋值,二、四通过stringWithFormat进行赋值 一、二赋值helloworld 三、四赋值hello(长度比上面的短)
看一下结果
一、三直接赋值不管长短,类型相同,地址相邻,都为__NSCFConstantString类型 二为__NSCFString类型,四为NSTaggedPointerString类型 来了解一下NSString的这三种类型
__NSCFConstantString
Constant->常量
- 通俗理解其就是常量字符串,是一种编译时常量
- 这种对象存储在字符串常量区。
- 通过打印起retainCount的值,发现很大,2^64 - 1,测试证明对其进行release操作时,retainCount不会产生任何变化是创建之后便无法释放掉的对象。
- 当我们使用不同的字符串对象进行创建时当内容相同,其对象的地址也相同,这也就证明了常量字符串是一种单例。
- 这种对象一般通过字面值 @"..."、CFSTR("...") (一种宏定义创建字符串的方法)或者 stringWithString: 方法(现在会报警告⚠️这个方法等同于字面值创建的方法)。
__NSCFString
- 和 __NSCFConstantString 不同, __NSCFString 对象是在运行时创建的一种 NSString 子类,他并不是一种字符串常量。所以和其他的对象一样在被创建时获得了 1 的引用计数。
- 这种对象被存储在堆上。
- 通过 NSString 的 stringWithFormat 等方法创建的 NSString 对象一般都是这种类型。
- 如果字符串长度大于9或者如果有中文或其他特殊符号(可能是非 ASCII 字符)存在的话则会直接成为 __NSCFString 类型
NSTaggedPointerString
标签指针的概念
理解这个类型,需要明白什么是标签指针,这是苹果在 64 位环境下对 NSString,NSNumber 等对象做的一些优化。
简单来讲可以理解为把指针指向的内容直接放在了指针变量的内存地址中,因为在 64 位环境下指针变量的大小达到了 8 字节足以容纳一些长度较小的内容。于是使用了标签指针这种方式来优化数据的存储方式。
- 从其的引用计数可以看出,这也是一个释放不掉的单例常量对象。当我们使用不同的字符串对象进行创建时当内容相同,其对象的地址也相同。在运行时根据实际情况创建。
- 对于 NSString 对象来讲,当非字面值常量的数字,英文字母字符串的长度小于等于 9 的时候会自动成为 NSTaggedPointerString 类型。(小于等于9这个数据也是原博主进行猜测,经过测试在字符串含有q的时候是小于等于7)
NSString的深浅复制问题
想看看__NSCFString和NSTaggedPointerString的copy和mutableCopy的结果是否一致
__NSCFString的字符串和我们之前理解的一样
NSTaggedPointerString也一样
常量字符串也和我们之前的理解一样 结束。
网友评论