iOS-深入理解NSString的三种存储类型

前瞻

在 Objective-C 的 Fondation 框架中 NSString 对象是很复杂的存在,各种方式创建以及不同长度的字符串都会影响 NSString 对象在内存中所处的位置。Objective-C 在运行时也对其做了很多优化。今天就来研究一下 NSString 这个复杂的对象。

NSString 类型的出现

  • 参考学长的博客,我们以四个字符串为例,分别用 @ 直接创建两个长短不一的,再分别用 stringWithFormat 创建两个长短不一的
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString* string1 = @"hello3GiOS";
        NSString* string2 = @"hello";
        NSString* string3 = [NSString stringWithFormat:@"hello3GiOS"];
        NSString* string4 = [NSString stringWithFormat:@"hello"];
        
        NSLog(@" \n%@ %p\n, %@ %p\n, %@ %p\n, %@ %p\n, ", [string1 class], string1, [string2 class], string2, [string3 class], string3, [string4 class], string4 );
    }
    return 0;
}
  • 打印结果

在这里插入图片描述

  • 我们发现对于用@ 直接创建的字符串的类型与长短无关
  • 但是用stringWithFormat 创建的字符串产生的类型就和长短有关
__NSCFConstantString

对于这个类型的NSString,我们测试打印他的retainCount

  NSString* string1 = @"hello3GiOS";
        NSString* string2 = @"hello";
        NSLog(@" string1的引用计数: %ld", CFGetRetainCount((__bridge  CFTypeRef)(string1)));
        NSLog(@" string2的引用计数: %ld", CFGetRetainCount((__bridge  CFTypeRef)(string2)));

请添加图片描述

  • 发现二者的引用计数是很大很大的数字,我们是ARC环境下(也即是自动释放池)进行测试的,如此一来说明他们不能被释放。
    它是创建之后便是放不掉的对象
    我们创建两个内容相同的对象试试
   NSString* string1 = @"hello3GiOS";
//        NSString* string2 = @"hello";
        NSString* string = @"hello3GiOS";
        NSLog(@"string1的地址:%p, string的地址 %p", string1, string);

请添加图片描述

在这里插入图片描述

  • 上面创建了两个内容,类型相同的字符串,结果发现他们的地址是相同的,这也就说明了 __NSCFConstantString 是一种创建以后无法被释放的单例
怎么出现__NSCFConstantString
  • 查阅资料
    • 上面测试的@“…” 可以产生 __NSCFConstantString
    • CFSTR(“…”) 可以产生 __NSCFConstantString
    • stringWithString 可以产生 __NSCFConstantString (此方法等同于@“…”) 可以忽略。
__NSCFString
  • 同样的打印 __NSCFString 的引用计数 和类型来测试
 NSString* string3 = [NSString stringWithFormat:@"hello3GiOS"];
        NSString* textString = [NSString stringWithFormat:@"hello3GiOS"];
        NSLog(@"string3的地址:%p 类型 %@, textString的地址 %p 类型 %@", string3,[string3 class], textString, [textString class]);
  • 类型和地址
    • 创建两个内容一样的 __NSCFString 他们的地址是不一样的
      在这里插入图片描述
  • 引用计数
    在这里插入图片描述
  • 查阅资料
  • 和 __NSCFConstantString 不同, __NSCFString 对象是在运行时创建的一种 NSString 子类,他并不是一种字符串常量。所以和其他的对象一样在被创建时获得了 1 的引用计数。
    通过 NSString 的 stringWithFormat 等方法创建的 NSString 对象一般都是这种类型(长度大于等于9)
NSTaggedPointerString
  • 测试类型,同一个内容的地址和引用计数
 NSString* string4 = [NSString stringWithFormat:@"hello"];
        NSString* testString = [NSString stringWithFormat:@"hello"];
        NSLog(@" string4的引用计数: %ld", CFGetRetainCount((__bridge  CFTypeRef)(string4)));
        NSLog(@" test的引用计数: %ld", CFGetRetainCount((__bridge  CFTypeRef)(testString)));
        NSLog(@"string4的地址:%p 类型 %@, teststring的地址 %p 类型 %@", string4, [string4 class], testString, [testString class]);

在这里插入图片描述

  • 可以看到NSTaggedPointerString 也是一种单例并且一旦创建就不会被释放
  • 查阅资料
  • 对于 NSString 对象来讲,当非字面值常量的数字,英文字母字符串的长度小于等于 9 的时候会自动成为 NSTaggedPointerString 类型,如果有中文或其他特殊符号(可能是非 ASCII 字符)存在的话则会直接成为 )__NSCFString 类型。
  • 转载博客
  • 理解这个类型,需要明白什么是标签指针,这是苹果在 64 位环境下对 NSString,NSNumber 等对象做的一些优化。简单来讲可以理解为把指针指向的内容直接放在了指针变量的内存地址中,因为在 64 位环境下指针变量的大小达到了 8 位足以容纳一些长度较小的内容。于是使用了标签指针这种方式来优化数据的存储方式,在运行时根据实际情况创建。
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值