探讨NSString和NSMutableString的内存问题以及copy和MutableCopy两个方法
NSString:
//main.m
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) {
@autoreleasepool { NSString *str1 = @"aaa";
NSString *str2 ;
NSString *str3 ;
NSString *str4 ;
NSString *str5 ;
NSString *str6 ; str2 = [NSString stringWithString:str1];
str3 = str1;
str4 = [[NSString alloc]initWithString:str1];
str5 = [str1 copy];
str6 = [str1 mutableCopy]; NSLog(@"@\"aaa\" address = %p", @"aaa"); // 输出字符串aaa的地址。
NSLog(@"change before:");
NSLog(@" str1 = %@", str1); // 输出字符串str1的内容
NSLog(@" str1 address = %p", str1); // 输出字符串str1的内容所在地址。
NSLog(@" str2 = %@", str2); // 输出字符串str2的内容
NSLog(@" str2 address = %p", str2); // 输出字符串str2的内容所在地址。
NSLog(@" str3 = %@", str3); // 输出字符串str3的内容
NSLog(@" str3 address = %p", str3); // 输出字符串str3的内容所在地址。
NSLog(@" str4 = %@", str4); // 输出字符串str4的内容
NSLog(@" str4 address = %p", str4); // 输出字符串str4的内容所在地址。
NSLog(@" str5 = %@", str5); // 输出字符串str5的内容
NSLog(@" str5 address = %p", str5); // 输出字符串str5的内容所在地址。
NSLog(@" str6 = %@", str6); // 输出字符串str6的内容
NSLog(@" str6 address = %p", str6); // 输出字符串str6的内容所在地址。 NSLog(@" ");
NSLog(@"@\"bbb\" address = %p", @"bbb"); NSLog(@"change after:");
str1 = @"bbb";
NSLog(@" str1 = %@", str1); //输出修改后str1的内容
NSLog(@" str1 address = %p", str1); //输出修改后str1的内容所在地址
NSLog(@" str2 = %@", str2); //输出修改后str2的内容
NSLog(@" str2 address = %p", str2); //输出修改后str2的内容所在地址
NSLog(@" str3 = %@", str3); //输出修改后str3的内容
NSLog(@" str3 address = %p", str3); //输出修改后str3的内容所在地址
NSLog(@" str4 = %@", str4); //输出修改后str4的内容
NSLog(@" str4 address = %p", str4); //输出修改后str4的内容所在地址
NSLog(@" str5 = %@", str5); //输出修改后str5的内容
NSLog(@" str5 address = %p", str5); //输出修改后str5的内容所在地址
NSLog(@" str6 = %@", str6); //输出修改后str6的内容
NSLog(@" str6 address = %p", str6); //输出修改后str6的内容所在地址 NSLog(@" @\"aaa\" address = %p", @"aaa"); //再次输出修改后字符串aaa的地址
运行结果: 1 -- ::49.451 copyTest[:] @"aaa" address = 0x100001050
-- ::49.452 copyTest[:] change before:
-- ::49.452 copyTest[:] str1 = aaa
-- ::49.452 copyTest[:] str1 address = 0x100001050
-- ::49.453 copyTest[:] str2 = aaa
-- ::49.453 copyTest[:] str2 address = 0x100001050
-- ::49.453 copyTest[:] str3 = aaa
-- ::49.453 copyTest[:] str3 address = 0x100001050
-- ::49.453 copyTest[:] str4 = aaa
-- ::49.453 copyTest[:] str4 address = 0x100001050
-- ::49.453 copyTest[:] str5 = aaa
-- ::49.453 copyTest[:] str5 address = 0x100001050
-- ::49.453 copyTest[:] str6 = aaa
-- ::49.453 copyTest[:] str6 address = 0x100203930
-- ::49.453 copyTest[:]
-- ::49.453 copyTest[:] @"bbb" address = 0x100001270
-- ::49.453 copyTest[:] change after:
-- ::49.453 copyTest[:] str1 = bbb
-- ::49.453 copyTest[:] str1 address = 0x100001270
-- ::49.453 copyTest[:] str2 = aaa
-- ::49.453 copyTest[:] str2 address = 0x100001050
-- ::49.454 copyTest[:] str3 = aaa
-- ::49.454 copyTest[:] str3 address = 0x100001050
-- ::49.454 copyTest[:] str4 = aaa
-- ::49.454 copyTest[:] str4 address = 0x100001050
-- ::49.454 copyTest[:] str5 = aaa
-- ::49.454 copyTest[:] str5 address = 0x100001050
-- ::49.454 copyTest[:] str6 = aaa
-- ::49.454 copyTest[:] str6 address = 0x100203930
-- ::49.454 copyTest[:] @"aaa" address = 0x100001050
Program ended with exit code:
结果分析:
(1)在定义str1时就先把字符串@"aaa"赋值给str1,输出时 @"aaa"和str1的地址相同,都是 0x100001050 。
(2)接着以三种不同的方式将str1赋值给str2, str3, str4
(3)再次给str1赋值,这次将字符串@"bbb"赋值给str1。 不同的是,我们在赋值前先输出一次字符串@"bbb"的地址,根据输出结果发现又与str1的地址相同,但地址已经发生变化 0x100001050 --> 0x100001270 。由此可以发现,不可变字符串NSString在第一次赋值时,指向一个内存空间,当它被再次被赋值于不同的字符串时,它会指向另一个内存空间,这与可变字符串NSMutableString不同(稍后会对NSMutableString进行测试)。
不可变字符串NSString的“不可变”我理解为是它引用的地址的那个内容不能改变,但是它引用的地址是可以改变的,有点拗口:
我把aaa赋值给str1,没有改变aaa这个字符串,当然也没有改变str1。当我再次赋值bbb给str1时,似乎是str1引用的地址-0x100001050 的内容(即aaa)改变成了bbb,其实不然。事实上我们是改变了str1引用的地址来实现这种“假象”的。str1的引用地址已经由 0x100001050(含有字符串aaa的地址)变为 0x100001270(含有字符串bbb的地址)。我们通过最后一行输出结果:字符串aaa的地址仍是 0x100001050,就可以知道在str1被bbb重新赋值的这个过程中aaa没有发生任何改变。
(4)str2,str3,str4的结果就很清晰了。他们都只是引用了aaa赋值给str1时的地址。所以他们都引用这个地址0x100001050,这个地址里面的内容也就是aaa了。
(5)str5,str6分别是str1使用copy和MutableCopy方法创建的副本。 根据输出可以看到在str1改变前,通过copy创建的副本str5引用的地址,与str1引用的地址相同-0x100001050;MutableCopy创建的副本引用的地址(0x100203930)则与str1的(0x100001050)不同。可以得出结论:对于不可变字符串NSString,copy方法创建的新副本不会分配新的内存空间,而MutableCopy创建的新副本会分配新的内存空间。
NSMutableString:
//main.m
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) {
@autoreleasepool { NSMutableString *str1 = [[NSMutableString alloc]initWithCapacity:];
NSMutableString *str2;
NSMutableString *str3;
NSMutableString *str4;
NSMutableString *str5;
NSMutableString *str6;
NSMutableString *str7; NSLog(@"@\"a\" address = %p", @"aaa");
NSLog(@"change before:");
str1 = [NSMutableString stringWithString:@"aaa"]; str2 = str1;
str3 = [NSMutableString stringWithString:str1];
str4 = [[NSMutableString alloc]initWithString:str1];
str5 = [[NSMutableString alloc]initWithCapacity:];
[str5 setString:str1];
str6 = [str1 copy];
str7 = [str1 mutableCopy]; NSLog(@"str1 = %@", str1); //输出str1内容
NSLog(@"str1 address = %p", str1); //输出str1内容所在的地址
NSLog(@"str2 = %@", str2); //输出str2内容
NSLog(@"str2 address = %p", str2); //输出str2内容所在的地址
NSLog(@"str3 = %@", str3); //输出str3内容
NSLog(@"str3 address = %p", str3); //输出str3内容所在的地址
NSLog(@"str4 = %@", str4); //输出str4内容
NSLog(@"str4 address = %p", str4); //输出str4内容所在的地址
NSLog(@"str5 = %@", str5); //输出str5内容
NSLog(@"str5 address = %p", str5); //输出str5内容所在的地址
NSLog(@"str6 = %@", str6); //输出str6内容
NSLog(@"str6 address = %p", str6); //输出str6内容所在的地址
NSLog(@"str7 = %@", str7); //输出str7内容
NSLog(@"str7 address = %p", str7); //输出str7内容所在的地址 NSLog(@" ");
NSLog(@"@\"bbb\" address = %p", @"bbb");
NSLog(@"change after:");
[str1 setString:@"bbb"];
NSLog(@"str1 = %@", str1); //输出修改后str1内容
NSLog(@"str1 address = %p", str1); //输出修改后str1内容所在地址
NSLog(@"str2 = %@", str2); //输出修改后str2内容
NSLog(@"str2 address = %p", str2); //输出修改后str2内容所在地址
NSLog(@"str3 = %@", str3); //输出修改后str3内容
NSLog(@"str3 address = %p", str3); //输出修改后str3内容所在地址
NSLog(@"str4 = %@", str4); //输出修改后str4内容
NSLog(@"str4 address = %p", str4); //输出修改后str4内容所在地址
NSLog(@"str5 = %@", str5); //输出修改后str5内容
NSLog(@"str5 address = %p", str5); //输出修改后str5内容所在地址
NSLog(@"str6 = %@", str6); //输出修改后str6内容
NSLog(@"str6 address = %p", str6); //输出修改后str6内容所在地址
NSLog(@"str7 = %@", str7); //输出修改后str7内容
NSLog(@"str7 address = %p", str7); //输出修改后str7内容所在地址 }
return ;
}
运行结果: 1 -- ::03.191 copyTest[:] @"a" address = 0x100001068
-- ::03.192 copyTest[:] change before:
-- ::03.192 copyTest[:] str1 = aaa
-- ::03.192 copyTest[:] str1 address = 0x1002001d0
-- ::03.192 copyTest[:] str2 = aaa
-- ::03.192 copyTest[:] str2 address = 0x1002001d0
-- ::03.192 copyTest[:] str3 = aaa
-- ::03.193 copyTest[:] str3 address = 0x1002002f0
-- ::03.193 copyTest[:] str4 = aaa
-- ::03.193 copyTest[:] str4 address = 0x103000000
-- ::03.193 copyTest[:] str5 = aaa
-- ::03.193 copyTest[:] str5 address = 0x100200350
-- ::03.193 copyTest[:] str6 = aaa
-- ::03.193 copyTest[:] str6 address = 0x61616135
-- ::03.193 copyTest[:] str7 = aaa
-- ::03.193 copyTest[:] str7 address = 0x1002004c0
-- ::03.193 copyTest[:]
-- ::03.193 copyTest[:] @"bbb" address = 0x1000012a8
-- ::03.193 copyTest[:] change after:
-- ::03.193 copyTest[:] str1 = bbb
-- ::03.193 copyTest[:] str1 address = 0x1002001d0
-- ::03.193 copyTest[:] str2 = bbb
-- ::03.193 copyTest[:] str2 address = 0x1002001d0
-- ::03.193 copyTest[:] str3 = aaa
-- ::03.194 copyTest[:] str3 address = 0x1002002f0
-- ::03.194 copyTest[:] str4 = aaa
-- ::03.194 copyTest[:] str4 address = 0x103000000
-- ::03.194 copyTest[:] str5 = aaa
-- ::03.194 copyTest[:] str5 address = 0x100200350
-- ::03.194 copyTest[:] str6 = aaa
-- ::03.194 copyTest[:] str6 address = 0x61616135
-- ::03.194 copyTest[:] str7 = aaa
-- ::03.194 copyTest[:] str7 address = 0x1002004c0
Program ended with exit code:
结果分析:
一、改变str1前:
(1)str2 = str1这种简单的赋值只是str2引用了str1引用的地址,所以地址相同-0x1002001d0。
(2)str3,str4,str5都分配了新的地址空间,3者的地址都不相同。在它们得到了新分配的地址后,以可变字符串str1为参数进行了赋值,但实质上只是提取str1引用的地址里面的内容,即字符串aaa,它们之间没有任何联系。
(3)str6,str7是str1分别用copy和MutableCopy方法创建的新副本,它们引用的地址都和str1的不同,且str6和str7也不同。这里与可变字符串NSString有差异,可见上文结果分析(5)。这里得出结论:可变字符串NSMutableString,使用copy和MutableCopy创建的新副本都会为它们分配新的内存空间。
二、改变str1后:
(1)str1和str2引用了同一个地址,str2自然随着str1的改变而改变。str1的内容就是str2的内容。但是我们这次要观察的重点是,str1的内容变了,但它的地址没有改变,修改前后都是-0x1002001d0。这里与可变字符串NSString有差异,可见上文结果分析(3)。
(2)str3,str4,str5,str6,str7都与str1不同,所以内容不会发生改变。
我们再做一个测试:
//main.m #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) {
@autoreleasepool { NSString *str1 = @"a";
NSMutableString *str2;
NSMutableString *str3; NSMutableString *str4 = [NSMutableString stringWithString:@"a"];
NSString *str5;
NSString *str6; //一个不可变字符串str1使用copy和MutableCopy创建两个新副本给2个可变字符串str2和str3
str2 = [str1 copy];
str3 = [str1 mutableCopy]; //一个可变字符串str4使用copy和MutableCopy创建两个新副本给2个不可变字符串str5和str6
str5 = [str4 copy];
str6 = [str4 mutableCopy]; NSLog(@"str1 address = %p", str1);
NSLog(@"str2 address = %p", str2);
NSLog(@"str3 address = %p", str3);
NSLog(@"str4 address = %p", str4);
NSLog(@"str5 address = %p", str5);
NSLog(@"str6 address = %p", str6); }
return ;
}
//运行结果: -- ::01.697 copyTest[:] str1 address = 0x100001050
-- ::01.698 copyTest[:] str2 address = 0x100001050
-- ::01.698 copyTest[:] str3 address = 0x100203980
-- ::01.698 copyTest[:] str4 address = 0x1002037b0
-- ::01.698 copyTest[:] str5 address = 0x6115
-- ::01.698 copyTest[:] str6 address = 0x100203a70
Program ended with exit code:
结果一目了然。不可变字符串的使用copy创建的新副本无论赋值给可变还是不可变字符串,都不会分配新的内存空间。
探讨NSString和NSMutableString的内存问题以及copy和MutableCopy两个方法的更多相关文章
- Objective-C学习篇06—NSString与NSMutableString
NSString OC提供了定义字符串对象的方法,也就是将想要表达的字符串用一对双引号引起来,并在开头加上@.@是OC中的指令符,它告诉编译器@以后的内容为OC中的语法.比如@”Harbingwang ...
- Foundation框架-NSString和NSMutableString
可变与不可变的字符串 --1-- Foundation框架介绍 1.1 框架介绍 --2-- NSString 2.1 NSString介绍及使用 2.2 NSString创建方式 2.3 从文件中 ...
- iOS基础-NSString及NSMutableString剖析
一.NSString头文件 NSString : NSObject 实现协议: NSCopying/NSMutableCopying/NSSecureCoding 类别: //扩展类别 NSStrin ...
- 14.Object-C--浅谈Foundation框架字符串NSString 与NSMutableString
OC的字符串时经常使用到的,今天我对于OC字符串做一个简单的总结,如果有错误之处,麻烦留言指正.感谢! NSString是一个不可变长度的字符串对象.表示它初始化以后,你不能改变该变量所分配的内存中的 ...
- 关于NSString和NSMutableString的相关用法和基本介绍
Objective-C 中核心处理字符串的类是 NSString 与 NSMutableString ,这两个类最大的区别就是NSString 创建赋值以后该字符串的内容与长度不能在动态的更改,除非重 ...
- NSString和NSMutablestring,copy和strong(转载)
1.http://www.cocoachina.com/ios/20150512/11805.html 2.http://blog.csdn.net/winzlee/article/details/5 ...
- NSString 与NSMutableString的区别
NSString 与NSMutableString的区别 Suppose You have a code like this NSString *s = [[NSString alloc] ...
- NSString和NSMutableString常用方法+NSArray常用代码 (转)
常见的NSString和NSMutableString方法: NSString方法: [plain] view plaincopy +(id) stringWithContentsOfFile:p ...
- OC之NSString、NSMutableString学习笔记 常用方法
NSString篇: 1.字符串连接 NSString *beijing = @"北京"; NSString *welcome = [beijing stringByAppendi ...
随机推荐
- EXTJS 4.2 资料 控件之隐藏显示setVisible、只读setDisabled
隐藏: form_Step3_1_left.form.findField('CPTypeId').setVisible(false); 显示: form_Step3_1_left.form.findF ...
- jquery全局加载函数的几种方式;
1.使用javascript方式(function(){})(); 2.使用jQuery(function($) {}); 3.使用$(document).ready(function(){}); 其 ...
- Weblogic12c安装与配置详解
Weblogic是什么Weblogic的安装Weblogic创建域Weblogic管理域Weblogic的应用Weblogic是什么 Weblogic这是我入职以后第一次接触到的词汇,我很陌生,就从我 ...
- 实现WebApp直接调起NativeApp
原文http://www.baidufe.com/item/3444ee051f8edb361d12.html 试了一个小Demo,从WebApp上直接调起Android Native App,包括应 ...
- C#列表顺序替换思想
/// <summary> /// 显示列顺序 /// </summary> /// <param name="list"></param ...
- hdu 4710 Balls Rearrangement()
http://acm.hdu.edu.cn/showproblem.php?pid=4710 [code]: #include <iostream> #include <cstdio ...
- WEB开发者必备的7个JavaScript函数
防止高频调用的debounce函数 这个 debounce 函数对于那些执行事件驱动的任务来说是必不可少的提高性能的函数.如果你在使用scroll, resize, key*等事件触发执行任务时不使用 ...
- [转载]LINQ 中的 select
下面通过一些例子来说明怎样使用select,参考自:LINQ Samples 1. 可以对查询出来的结果做一些转换,下面的例子在数组中查找以"B"开头的名字,然后全部转成小写输出 ...
- hdu 3449
有依赖的背包,转化成01背包来做: #include<iostream> #include<cstdio> #include<cstring> #include&l ...
- uva 825
这个......小学生就会的 坑在输入输出了 两个数之间可能不止一个空格....wa了好几遍啊 #include <cstdio> #include <cstring> # ...