NSString有哪些创建对象的方法?创建的对象分别存储在什么区域?

NSString有哪些创建对象的方法?创建的对象分别存储在什么区域?

一般通过NSString创建对象的方法有:

  1. NSString *string1 = @"123";
  2. NSString *string2 = [[NSString alloc] initWithString:@"123"];
  3. NSString *string3 = [NSString stringWithFormat:@"123"];
  4. NSString *string4 = [[NSString alloc] initWithFormat:@"123"];

这里面涉及到几个问题:
创建的对象存储在什么区?常量区?堆区?还是小对象?

因此,我们做打印,看结果分析:

//目的:看看字符串长度短的情况下
NSString *string0 = @"sun";//常量区
//目的:看看字符串长度很长的情况下
NSString *string1 = @"sundaopjd2221";//常量区
        
NSString *string2 = [[NSString alloc] init];//常量区
NSString *string3 = [[NSString alloc] initWithString:@"sun"];//常量区
//目的:看看字符串长度短的情况下,下一个存储空间地址是啥
NSString *string4 = [[NSString alloc] initWithString:@"sun2"];//常量区
//目的:看看字符串长度很长的情况下,有没有变化
NSString *string5 = [[NSString alloc] initWithString:@"sundaopjd2221"];//常量区
        
//目的:看看字符串长度短的情况下,存储空间地址
NSString *string6 = [NSString stringWithFormat:@"1"];//小对象
//目的:看看字符串长度短的情况下,下一个存储空间地址是啥
NSString *string7 = [NSString stringWithFormat:@"2"];//小对象
//目的:看看字符串长度很长的情况下,有没有变化
NSString *string8 = [NSString stringWithFormat:@"sundaopjd2221"];//存储在堆
//目的:观察堆空间的变化
NSString *string9 = [NSString stringWithFormat:@"sundaopjd222122"];//存储在堆

//目的:看看字符串长度短的情况下,存储空间地址
NSString *string10 = [[NSString alloc] initWithFormat:@"1"];//小对象
//目的:看看字符串长度短的情况下,下一个存储空间地址是啥
NSString *string11 = [[NSString alloc] initWithFormat:@"3"];//小对象
//目的:看看字符串长度很长的情况下,有没有变化
NSString *string12 = [[NSString alloc] initWithFormat:@"sundaopjd2221"];//存储在堆
//目的:观察堆空间的变化
NSString *string13 = [[NSString alloc] initWithFormat:@"sundaopjd2221222"];//存储在堆

//这个是指针本身的存储地址(栈)
NSLog(@"%p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p", &string0, &string1, &string2, &string3, &string4, &string5, &string6, &string7, &string8, &string9, &string10, &string11, &string12, &string13);
        
//看看string的类型
NSLog(@"%@, %@, %@, %@, %@, %@, %@, %@, %@, %@, %@, %@, %@, %@", [string0 class], [string1 class], [string2 class], [string3 class], [string4 class], [string5 class], [string6 class], [string7 class], [string8 class], [string9 class], [string10 class], [string11 class], [string12 class], [string13 class]);

//这个是对象存储的地址
NSLog(@"%p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p", string0, string1, string2, string3, string4, string5, string6, string7, string8, string9, string10, string11, string12, string13);
        
//看看引用计数器个数
NSLog(@"%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", [string0 retainCount], [string1 retainCount], [string2 retainCount], [string3 retainCount], [string4 retainCount], [string5 retainCount], [string6 retainCount], [string7 retainCount], [string8 retainCount], [string9 retainCount], [string10 retainCount], [string11 retainCount], [string12 retainCount], [string13 retainCount]);

打印结果:
0x7ff7bfeff290, 0x7ff7bfeff288, 0x7ff7bfeff280, 0x7ff7bfeff278, 0x7ff7bfeff270, 0x7ff7bfeff268, 0x7ff7bfeff260, 0x7ff7bfeff258, 0x7ff7bfeff250, 0x7ff7bfeff248, 0x7ff7bfeff240, 0x7ff7bfeff238, 0x7ff7bfeff230, 0x7ff7bfeff228

__NSCFConstantString, __NSCFConstantString, __NSCFConstantString, __NSCFConstantString, __NSCFConstantString, __NSCFConstantString, NSTaggedPointerString, NSTaggedPointerString, __NSCFString, __NSCFString, NSTaggedPointerString, NSTaggedPointerString, __NSCFString, __NSCFString

//混淆关闭前
//0x100004038, 0x100004058, 0x7ff846c7c2d0, 0x100004038, 0x100004078, 0x100004058, 0x9329a7a56318529b, 0x9329a7a56318519b, 0x600000207100, 0x600000c04ba0, 0x9329a7a56318529b, 0x9329a7a56318509b, 0x600000207120, 0x600000c04bd0
//混淆关闭后
0x100004038, 0x100004058, 0x7ff846c7c2d0, 0x100004038, 0x100004078, 0x100004058, 0x3115, 0x3215, 0x600000209340, 0x600000c0cba0, 0x3115, 0x3215, 0x3315, 0x600000c0cbd0

-1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1

分析:

通过打印[string class]获取的类型:__NSCFConstantString,NSTaggedPointerString,__NSCFString
可以知道创建的对象分别存储在什么区:常量区、小对象、堆区

通过打印[string retainCount]获取引用计数器:-1,1的结果,可以区分:
-1:常量区或小对象
1:堆区

问:为啥retainCount会为-1?

这是因为retainCount是一个无符号整型typedef unsigned long NSUInteger;
因此,-1并不代表是真正的引用计数器的值

在iOS中,遇到retainCount返回-1(或者在某些情况下是UINT_MAX,因为retainCount返回的是NSUInteger,一个无符号整型)通常是指对象被标记为不可释放或具有“无限”的引用计数。这种情况通常发生在几种特殊对象上,这些对象由于各种原因,被系统视为“永久存活”的,直到应用程序结束。这样的对象不参与常规的引用计数管理,也就是说,无论对它们进行多少次retainrelease操作,它们都不会被销毁。

这里的-1或UINT_MAX并不表示实际的引用计数值,而是一个标志,表明这个对象是由系统以特殊方式管理的。对于开发者来说,这意味着这类对象的内存管理并不需要(也不应该)手动干预。

几个典型的例子包括:

  • 单例对象:如[UIApplication sharedApplication][NSFileManager defaultManager],这些单例在应用程序的整个生命周期内都应该保持活跃状态。
  • 字符串字面量:如NSString *str = @"constant string";,这些字符串在编译时被创建,并存储在应用程序的二进制文件中。它们在整个应用程序的生命周期内都是有效的,因此被认为是具有“无限”引用计数的。
  • 标准框架对象:某些由系统框架创建并管理的对象,可能也会被标记为具有“无限”引用计数。

结论:

  • 通过NSString *str = @"1"[NSString alloc] initWithString:@"1"]创建的对象一致,都是存储在常量区

虽然有initWithString,有init,但也是放在常量区,不增加引用计数器

  • 通过[NSString stringWithFormat:@"2"];[[NSString alloc] initWithFormat:@"2"];创建的对象一致,当字符串长度小的时候(小于10)都是小对象,字符串长度过长的时候(大于等于10)存储在堆区域
//9个数
NSString *string11 = [[NSString alloc] initWithFormat:@"123456789"];
//10个数
NSString *string12 = [[NSString alloc] initWithFormat:@"1234567890"];
打印类型结果:
NSTaggedPointerString, __NSCFString
  • 小对象的引用,与小对象本身的地址不一致,即NSString *string6 = [NSString stringWithFormat:@"1"]; string6的地址,与[NSString stringWithFormat:@"1"];的地址不一致。
    因为string6是在栈上的,然后string6内部有一部分特定区域,存放小对象"1"

猜测:小对象存储在栈区

在这里插入图片描述

在这里插入图片描述

在现在的版本中,为了保证数据安全,苹果对 Tagged Pointer 做了数据混淆,开发者通过打印指针无法判断它是不是一个Tagged Pointer,更无法读取Tagged Pointer的存储数据。
所以在分析Tagged Pointer之前,我们需要先关闭Tagged Pointer的数据混淆,以方便我们调试程序。通过设置环境变量OBJC_DISABLE_TAG_OBFUSCATION为YES。

iOS - 老生常谈内存管理(五):Tagged Pointer

相关推荐

  1. Spring(创建对象方式3个)

    2024-03-31 05:06:08       18 阅读
  2. 虚拟机对象创建

    2024-03-31 05:06:08       34 阅读
  3. 工厂方法模式:灵活创建对象实例

    2024-03-31 05:06:08       13 阅读
  4. 关于JVM对象创建小知识

    2024-03-31 05:06:08       35 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-31 05:06:08       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-31 05:06:08       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-31 05:06:08       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-31 05:06:08       18 阅读

热门阅读

  1. Python之旅:你能学到什么?

    2024-03-31 05:06:08       16 阅读
  2. RPM与YUM

    RPM与YUM

    2024-03-31 05:06:08      14 阅读
  3. go通道使用案例

    2024-03-31 05:06:08       15 阅读
  4. PhpWord导入试题

    2024-03-31 05:06:08       15 阅读
  5. 解决Nginx常见问题的技术指南

    2024-03-31 05:06:08       16 阅读
  6. leetcode自练题目

    2024-03-31 05:06:08       19 阅读
  7. 探究Mark Text: 新兴的全平台Markdown编辑器

    2024-03-31 05:06:08       17 阅读
  8. 【React】vite + react 项目,安装、配置、使用 less

    2024-03-31 05:06:08       16 阅读