copy 和 mutableCopy 有点乱
字符串的拷贝操作
对 string literal (字符串字面量) 执行 copy
要打印指针指向对象的地址和指针本身的地址,可以使用 %p
格式符来输出指针地址。以下代码,展示了 originalString
和 copiedString
的指针地址和指向对象的地址:
NSString *originalString = @"Hello, World!";
NSString *copiedString = [originalString copy];// 打印字符串内容
NSLog(@"Original: %@", originalString); // 输出: Hello, World!
NSLog(@"Copied: %@", copiedString); // 输出: Hello, World!// 打印指针本身的地址
NSLog(@"Original pointer address: %p", &originalString);
NSLog(@"Copied pointer address: %p", &copiedString);// 打印指针指向对象的地址
NSLog(@"Original object address: %p", originalString);
NSLog(@"Copied object address: %p", copiedString);
Xcode Version 15.1 (15C65) & 模拟器(iPhone 15)运行结果如下:
// 打印的内容一样
Original: Hello, World!
Copied: Hello, World!
// 指针本地的地址不一样,说明是不同的指针
Original pointer address: 0x7ff7b1a5fa98
Copied pointer address: 0x7ff7b1a5fa90
// 不同的指针指向同一个对象
Original object address: 0x10e4a0070
Copied object address: 0x10e4a0070
解释
Original: Hello, World!
和Copied: Hello, World!
输出字符串内容。Original pointer address: %p
输出指针originalString
本身在栈中的地址。Copied pointer address: %p
输出指针copiedString
本身在栈中的地址。Original object address: %p
输出originalString
指向的字符串对象在堆中的地址。Copied object address: %p
输出copiedString
指向的字符串对象在堆中的地址。
可以看到,由于 NSString
是不可变对象,执行 copy
方法时并不会产生新的对象,而是返回相同的对象。所以 originalString
和 copiedString
指向相同的内存地址(对象地址相同),但是它们的指针本身在栈中的地址是不同的。
对 string literal (字符串字面量) 执行 mutableCopy
NSString *originalString = @"Hello, World!";NSString *copiedString = [originalString mutableCopy];// 打印字符串内容NSLog(@"Original: %@", originalString); // 输出: Hello, World!NSLog(@"Copied: %@", copiedString); // 输出: Hello, World!// 打印指针本身的地址NSLog(@"Original pointer address: %p", &originalString);NSLog(@"Copied pointer address: %p", &copiedString);// 打印指针指向对象的地址NSLog(@"Original object address: %p", originalString);NSLog(@"Copied object address: %p", copiedString);
Xcode Version 15.1 (15C65) & 模拟器(iPhone 15)运行结果如下:
Original: Hello, World!
Copied: Hello, World!
// 不同的指针
Original pointer address: 0x7ff7be102a98
Copied pointer address: 0x7ff7be102a90
// 指向不同的对象
Original object address: 0x101dfd070
Copied object address: 0x600000c80090
对 mutable string 执行 copy
NSString *originalString = [NSMutableString stringWithString:@"Hello, World!"];NSString *copiedString = [originalString copy];NSString *doubleCopiedString = [copiedString copy];// 打印字符串内容NSLog(@"Original: %@", originalString); // 输出: Hello, World!NSLog(@"Copied: %@", copiedString); // 输出: Hello, World!NSLog(@"doubleCopied: %@", doubleCopiedString); // 输出: Hello, World!// 打印指针本身的地址NSLog(@"Original pointer address: %p", &originalString);NSLog(@"Copied pointer address: %p", &copiedString);NSLog(@"Double copied pointer address: %p", &doubleCopiedString);// 打印指针指向对象的地址NSLog(@"Original object address: %p", originalString);NSLog(@"Copied object address: %p", copiedString);NSLog(@"Double copied object address: %p", doubleCopiedString);
Xcode Version 15.1 (15C65) & 模拟器(iPhone 15)运行结果如下:
Original: Hello, World!
Copied: Hello, World!
doubleCopied: Hello, World!
Original pointer address: 0x7ff7be573a98
Copied pointer address: 0x7ff7be573a90
Double copied pointer address: 0x7ff7be573a88
Original object address: 0x600000c05e30
Copied object address: 0x600000240fa0
Double copied object address: 0x600000240fa0
对 mutable string 执行 mutableCopy
NSString *originalString = [NSMutableString stringWithString:@"Hello, World!"];NSString *copiedString = [originalString mutableCopy];NSString *doubleCopiedString = [copiedString mutableCopy];// 打印字符串内容NSLog(@"Original: %@", originalString); // 输出: Hello, World!NSLog(@"Copied: %@", copiedString); // 输出: Hello, World!NSLog(@"doubleCopied: %@", doubleCopiedString); // 输出: Hello, World!// 打印指针本身的地址NSLog(@"Original pointer address: %p", &originalString);NSLog(@"Copied pointer address: %p", &copiedString);NSLog(@"Double copied pointer address: %p", &doubleCopiedString);// 打印指针指向对象的地址NSLog(@"Original object address: %p", originalString);NSLog(@"Copied object address: %p", copiedString);NSLog(@"Double copied object address: %p", doubleCopiedString);
Original: Hello, World!
Copied: Hello, World!
doubleCopied: Hello, World!
Original pointer address: 0x7ff7b7523a98
Copied pointer address: 0x7ff7b7523a90
Double copied pointer address: 0x7ff7b7523a88
Original object address: 0x600000c7c510
Copied object address: 0x600000c7c6c0
Double copied object address: 0x600000c7c9f0
拓展 - 什么是字符串驻留(String Interning)
在编程语言中,字符串驻留(String Interning)是一种优化技术,用于减少内存使用和提高字符串比较的效率。它通过确保相同内容的字符串只在内存中存储一份,从而避免重复创建相同的字符串对象。
字符串驻留的工作原理
字符串驻留的基本思想是将相同内容的字符串存储在一个全局的字符串池中。当需要创建一个新字符串时,先检查这个字符串池中是否已经存在相同内容的字符串。如果存在,则直接返回池中已有的字符串的引用;如果不存在,则创建新字符串并将其添加到字符串池中。
字符串驻留的优点
- 节省内存:通过避免存储多个相同内容的字符串,字符串驻留可以显著减少内存使用。
- 提高字符串比较的效率:由于驻留的字符串是唯一的,比较两个字符串是否相同只需要比较它们的引用(指针),而不需要逐字符比较内容。这使得字符串比较操作非常高效。
字符串驻留在 Objective-C 中的应用
在 Objective-C 中,编译器和运行时环境对字符串常量进行了优化,使得相同的字符串常量在内存中只存在一份。这种优化由编译器和运行时自动处理,开发者无需额外干预。
以下是一个示例,展示了字符串常量驻留的效果:
NSString *string1 = @"Hello, World!";
NSString *string2 = @"Hello, World!";NSLog(@"%p", string1); // 输出某个地址
NSLog(@"%p", string2); // 输出与 string1 相同的地址
在这个示例中,string1
和 string2
指向相同的内存地址,因为编译器对字符串常量进行了驻留优化。
动态创建的字符串
与字符串常量不同,动态创建的字符串(例如通过 stringWithFormat:
、initWithString:
等方法创建的字符串)不会自动进行驻留。即使它们的内容相同,它们在内存中的地址也可能不同:
NSString *dynamicString1 = [NSString stringWithFormat:@"Hello, World!"];
NSString *dynamicString2 = [NSString stringWithFormat:@"Hello, World!"];NSLog(@"%p", dynamicString1); // 输出某个地址
NSLog(@"%p", dynamicString2); // 输出不同的地址
在这个示例中,dynamicString1
和 dynamicString2
指向不同的内存地址,因为它们是动态创建的字符串对象。
强制字符串驻留
虽然动态创建的字符串不会自动驻留,但可以通过调用 NSString
的 intern
方法(注意,这在 Objective-C 中并不是一个标准方法,而是在某些语言中存在)将字符串显式地添加到驻留池中。例如,在 Java 中有 String.intern()
方法,但在 Objective-C 中并没有直接的等效方法。
小结
字符串驻留(String Interning)是一种有效的优化技术,广泛应用于各种编程语言中。在 Objective-C 中,字符串常量会自动进行驻留,而动态创建的字符串则不会。理解字符串驻留的机制有助于优化内存使用和提高程序的性能。
希望这篇博客能帮助你更好地理解字符串驻留的概念及其在实际编程中的应用。如果你有任何问题或需要进一步的解释,请随时联系我!
参考资料
- Apple Developer Documentation
- Objective-C Programming Guide
- String Interning - Wikipedia
相关文章:
copy 和 mutableCopy 有点乱
字符串的拷贝操作 对 string literal (字符串字面量) 执行 copy 要打印指针指向对象的地址和指针本身的地址,可以使用 %p 格式符来输出指针地址。以下代码,展示了 originalString 和 copiedString 的指针地址和指向对象的地址: NSString *…...
sqlalchemy通过查询参数生成query
sqlalchemy通过查询参数生成query 在SQLAlchemy中,可以使用查询参数来动态生成查询。这通常通过使用.filter()方法和Python的比较运算符来实现。以下是一个简单的示例,展示如何使用查询参数生成查询: 假设我们有一个名为User的模型(表),它具有id、username和email字段。…...

【JavaScript 算法】二分查找:快速定位目标元素
🔥 个人主页:空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 二分查找(Binary Search)是一种高效的查找算法,适用于在有序数组中快速定位目标元素。相比于线性查找,二分查找…...

论文研读:ViT-V-Net—用于无监督3D医学图像配准的Vision Transformer
目录 摘要 介绍 方法 VIT-V-Net体系结构 损失函数 图像相似性度量 变形场正则化 结果与讨论 摘要 在过去的十年里,卷积神经网络(ConvNets)在各种医学成像应用中占据了主导地位并取得了最先进的性能。然而,由于缺乏对图像中远程空间关系的理解&a…...

C++入门到进阶(图文详解,持续更新中)
C入门到进阶(图文详解,持续更新中) 详解C入门知识到进阶,配合图观看易于理解记录 文章目录 目录 C入门到进阶(图文详解,持续更新中) 文章目录 前言 一、数据 (一)数据类…...
【React Hooks原理 - useRef】
概述 在Function Component项目中当我们需要操作dom的时候,第一时间想到的就是使用useRef这个Hook来绑定dom。但是这个仅仅是使用这个Hook而已,为了更好的学习React Hooks内部实现原理,知其所以然。所以本文根据源码从useRef的基础使用场景一…...

MVC之 IHttpModule管道模型《二》
》》》注意:在http请求的处理过程中,只能调用一个HttpHandler,但可以调用多个HttpModule。 HTTP Modules ASP.NET请求处理过程是基于管道模型的,这个管道模型是由多个HttpModule和HttpHandler组成,当请求到达HttpMod…...

2025上海纺织助剂展会+上海织物整理剂展
2025上海纺织助剂展会上海织物整理剂展 2025第十二届中国(上海)纺织助剂及织物整理剂展览会 时间: 2025年4月23-25日 地点:上海跨国采购会展中心(光复西路2739号) 展会简介: 2025第12届中国(上海&#…...

中科亿海微亮相慕尼黑上海电子展
7月8-10日,备受瞩目的全球电子行业盛会“慕尼黑上海电子展”以空前规模启幕,汇聚了超过1600家参展企业,涵盖了从终端产品制造商到元器件供应商、组装/系统供应商、EMS、ODM/OEM、材料供应商及生产设备供应商的完整产业链。中科亿海微电子科技…...
Spring boot 2.0 升级到 3.3.1 的相关问题 (一)
文章目录 Spring boot 2.0 升级到 3.3.1 的相关问题 (一)拦截器Interceptor的变动问题介绍解决方案 WebMvcConfigurerAdapter 自定义Mvc配置问题介绍解决方案 Spring boot 2.0 升级到 3.3.1 的相关问题 (一) 拦截器Interceptor的…...
数据分析——Python网络爬虫(四){爬虫库的使用}
爬虫库 爬虫的步骤urllib库发送请求两种方法案例 爬虫的步骤 #mermaid-svg-h5azjtPInpsU2ZpP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-h5azjtPInpsU2ZpP .error-icon{fill:#552222;}#mermaid-svg-h5azjtPInps…...

C++客户端Qt开发——信号和槽
三、信号和槽 1.信号和槽概述 在Qt中,用户和控件的每次交互过程称为一个事件。比如"用户点击按钮”是一个事件,"用户关闭窗口”也是一个事件。每个事件都会发出一个信号,例如用户点击按钮会发出"按钮被点击"的信号&…...

基于双向长短期记忆 BiLSTM 实现股票单变量时间序列预测(PyTorch版)
前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对…...

微信小程序毕业设计-汽车维修项目管理系统项目开发实战(附源码+论文)
大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:微信小程序毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计…...

学习大数据DAY16 PLSQL基础语法5
目录 异常 自定义异常的格式 raise_application_error 处理异常 预定义异常 SQLcode和SQLerrm 非预定义异常 作业 触发器 触发器基本概念 DML触发器 DML触发器使用 instead of 触发器 管理触发器 作业2 函数、过程和包 函数 过程 参数 1. in 参数 2.out 参…...

LabVIEW心电信号自动测试系统
开发了一种基于LabVIEW的心电信号自动测试系统,通过LabVIEW开发的上位机软件,实现对心电信号的实时采集、分析和自动化测试。系统包括心电信号采集模块、信号处理模块和自动化测试模块,能够高效、准确地完成心电信号的测量与分析。 硬件系统…...

最值得推荐的10款Windows软件!
AI视频生成:小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频播放量破百万https://aitools.jurilu.com/1.音乐播放器——Dopamine Dopamine是一款音乐播放器,设计简洁美观。它支持多种音频格式,包括wav、mp3、ogg…...

游戏视频是后期配音好还是边录边配 游戏视频怎么剪辑制作才能火 视频剪辑免费软件
游戏视频后期配音是先配还是先剪?游戏视频后期配音没有统一的准则,可以先配,也可以后配,主要是根据内容而定。游戏视频剪辑在游戏玩家中十分流行,那么,游戏视频怎么剪辑制作?下面让我们以具体的…...
配置 Node.js 内存限制
配置 Node.js 内存限制 Node.js 应用程序通常需要配置堆内存的大小以优化性能和避免内存溢出问题。你可以通过命令行参数、环境变量或系统属性来设置 Node.js 的内存限制。下面将分别介绍在 Windows、Linux 和 macOS 系统下的配置方法。 Windows 系统 1. 命令行参数方式 在…...
ORA-12518: TNS: 监听程序无法分发客户机连接
ORA-12518: TNS: 监听程序无法分发客户机连接 OracleService 服务停止了,启动就好了...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)
旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据!该数据集源自2025年4月发表于《地理学报》的论文成果…...

大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...
FTXUI::Dom 模块
DOM 模块定义了分层的 FTXUI::Element 树,可用于构建复杂的终端界面,支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...

云原生时代的系统设计:架构转型的战略支点
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、云原生的崛起:技术趋势与现实需求的交汇 随着企业业务的互联网化、全球化、智能化持续加深,传统的 I…...