探讨NSString和NSMutableString的内存问题以及copy和MutableCopy两个方法

NSString:
 1 //main.m
 2 #import <Foundation/Foundation.h>
 3
 4 int main(int argc, const char * argv[]) {
 5     @autoreleasepool {
 6
 7         NSString *str1 = @"aaa";
 8         NSString *str2 ;
 9         NSString *str3 ;
10         NSString *str4 ;
11         NSString *str5 ;
12         NSString *str6 ;
13
14
15
16         str2 = [NSString stringWithString:str1];
17         str3 = str1;
18         str4 = [[NSString alloc]initWithString:str1];
19         str5 = [str1 copy];
20         str6 = [str1 mutableCopy];
21
22         NSLog(@"@\"aaa\" address = %p", @"aaa");    // 输出字符串aaa的地址。
23         NSLog(@"change before:");
24         NSLog(@" str1 = %@", str1);           // 输出字符串str1的内容
25         NSLog(@" str1 address = %p", str1);    // 输出字符串str1的内容所在地址。
26         NSLog(@" str2 = %@", str2);           // 输出字符串str2的内容
27         NSLog(@" str2 address = %p", str2);    // 输出字符串str2的内容所在地址。
28         NSLog(@" str3 = %@", str3);           // 输出字符串str3的内容
29         NSLog(@" str3 address = %p", str3);    // 输出字符串str3的内容所在地址。
30         NSLog(@" str4 = %@", str4);           // 输出字符串str4的内容
31         NSLog(@" str4 address = %p", str4);    // 输出字符串str4的内容所在地址。
32         NSLog(@" str5 = %@", str5);           // 输出字符串str5的内容
33         NSLog(@" str5 address = %p", str5);    // 输出字符串str5的内容所在地址。
34         NSLog(@" str6 = %@", str6);           // 输出字符串str6的内容
35         NSLog(@" str6 address = %p", str6);    // 输出字符串str6的内容所在地址。
36
37         NSLog(@" ");
38         NSLog(@"@\"bbb\" address = %p", @"bbb");
39
40         NSLog(@"change after:");
41         str1 = @"bbb";
42         NSLog(@" str1 = %@", str1);      //输出修改后str1的内容
43         NSLog(@" str1 address = %p", str1);  //输出修改后str1的内容所在地址
44         NSLog(@" str2 = %@", str2);    //输出修改后str2的内容
45         NSLog(@" str2 address = %p", str2);  //输出修改后str2的内容所在地址
46         NSLog(@" str3 = %@", str3);   //输出修改后str3的内容
47         NSLog(@" str3 address = %p", str3);  //输出修改后str3的内容所在地址
48         NSLog(@" str4 = %@", str4);  //输出修改后str4的内容
49         NSLog(@" str4 address = %p", str4);  //输出修改后str4的内容所在地址
50         NSLog(@" str5 = %@", str5);  //输出修改后str5的内容
51         NSLog(@" str5 address = %p", str5);  //输出修改后str5的内容所在地址
52         NSLog(@" str6 = %@", str6);  //输出修改后str6的内容
53         NSLog(@" str6 address = %p", str6);  //输出修改后str6的内容所在地址
54
55         NSLog(@" @\"aaa\" address = %p", @"aaa"); //再次输出修改后字符串aaa的地址
 运行结果:

 1 2016-06-05 14:29:49.451 copyTest[1526:60199] @"aaa" address = 0x100001050
 2 2016-06-05 14:29:49.452 copyTest[1526:60199] change before:
 3 2016-06-05 14:29:49.452 copyTest[1526:60199]  str1 = aaa
 4 2016-06-05 14:29:49.452 copyTest[1526:60199]  str1 address = 0x100001050
 5 2016-06-05 14:29:49.453 copyTest[1526:60199]  str2 = aaa
 6 2016-06-05 14:29:49.453 copyTest[1526:60199]  str2 address = 0x100001050
 7 2016-06-05 14:29:49.453 copyTest[1526:60199]  str3 = aaa
 8 2016-06-05 14:29:49.453 copyTest[1526:60199]  str3 address = 0x100001050
 9 2016-06-05 14:29:49.453 copyTest[1526:60199]  str4 = aaa
10 2016-06-05 14:29:49.453 copyTest[1526:60199]  str4 address = 0x100001050
11 2016-06-05 14:29:49.453 copyTest[1526:60199]  str5 = aaa
12 2016-06-05 14:29:49.453 copyTest[1526:60199]  str5 address = 0x100001050
13 2016-06-05 14:29:49.453 copyTest[1526:60199]  str6 = aaa
14 2016-06-05 14:29:49.453 copyTest[1526:60199]  str6 address = 0x100203930
15 2016-06-05 14:29:49.453 copyTest[1526:60199]
16 2016-06-05 14:29:49.453 copyTest[1526:60199] @"bbb" address = 0x100001270
17 2016-06-05 14:29:49.453 copyTest[1526:60199] change after:
18 2016-06-05 14:29:49.453 copyTest[1526:60199]  str1 = bbb
19 2016-06-05 14:29:49.453 copyTest[1526:60199]  str1 address = 0x100001270
20 2016-06-05 14:29:49.453 copyTest[1526:60199]  str2 = aaa
21 2016-06-05 14:29:49.453 copyTest[1526:60199]  str2 address = 0x100001050
22 2016-06-05 14:29:49.454 copyTest[1526:60199]  str3 = aaa
23 2016-06-05 14:29:49.454 copyTest[1526:60199]  str3 address = 0x100001050
24 2016-06-05 14:29:49.454 copyTest[1526:60199]  str4 = aaa
25 2016-06-05 14:29:49.454 copyTest[1526:60199]  str4 address = 0x100001050
26 2016-06-05 14:29:49.454 copyTest[1526:60199]  str5 = aaa
27 2016-06-05 14:29:49.454 copyTest[1526:60199]  str5 address = 0x100001050
28 2016-06-05 14:29:49.454 copyTest[1526:60199]  str6 = aaa
29 2016-06-05 14:29:49.454 copyTest[1526:60199]  str6 address = 0x100203930
30 2016-06-05 14:29:49.454 copyTest[1526:60199]  @"aaa" address = 0x100001050
31 Program ended with exit code: 0

结果分析:

(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:

 1 //main.m
 2 #import <Foundation/Foundation.h>
 3
 4 int main(int argc, const char * argv[]) {
 5     @autoreleasepool {
 6
 7         NSMutableString *str1 = [[NSMutableString alloc]initWithCapacity:0];
 8         NSMutableString *str2;
 9         NSMutableString *str3;
10         NSMutableString *str4;
11         NSMutableString *str5;
12         NSMutableString *str6;
13         NSMutableString *str7;
14
15
16         NSLog(@"@\"a\" address = %p", @"aaa");
17         NSLog(@"change before:");
18         str1 = [NSMutableString stringWithString:@"aaa"];
19
20         str2 = str1;
21         str3 = [NSMutableString stringWithString:str1];
22         str4 = [[NSMutableString alloc]initWithString:str1];
23         str5 = [[NSMutableString alloc]initWithCapacity:0];
24         [str5 setString:str1];
25         str6 = [str1 copy];
26         str7 = [str1 mutableCopy];
27
28         NSLog(@"str1 = %@", str1);            //输出str1内容
29         NSLog(@"str1 address = %p", str1);    //输出str1内容所在的地址
30         NSLog(@"str2 = %@", str2);            //输出str2内容
31         NSLog(@"str2 address = %p", str2);    //输出str2内容所在的地址
32         NSLog(@"str3 = %@", str3);            //输出str3内容
33         NSLog(@"str3 address = %p", str3);       //输出str3内容所在的地址
34         NSLog(@"str4 = %@", str4);            //输出str4内容
35         NSLog(@"str4 address = %p", str4);   //输出str4内容所在的地址
36         NSLog(@"str5 = %@", str5);          //输出str5内容
37         NSLog(@"str5 address = %p", str5);   //输出str5内容所在的地址
38         NSLog(@"str6 = %@", str6);          //输出str6内容
39         NSLog(@"str6 address = %p", str6);   //输出str6内容所在的地址
40         NSLog(@"str7 = %@", str7);           //输出str7内容
41         NSLog(@"str7 address = %p", str7);    //输出str7内容所在的地址
42
43         NSLog(@" ");
44         NSLog(@"@\"bbb\" address = %p", @"bbb");
45         NSLog(@"change after:");
46         [str1 setString:@"bbb"];
47         NSLog(@"str1 = %@", str1);            //输出修改后str1内容
48         NSLog(@"str1 address = %p", str1);    //输出修改后str1内容所在地址
49         NSLog(@"str2 = %@", str2);             //输出修改后str2内容
50         NSLog(@"str2 address = %p", str2);     //输出修改后str2内容所在地址
51         NSLog(@"str3 = %@", str3);            //输出修改后str3内容
52         NSLog(@"str3 address = %p", str3);     //输出修改后str3内容所在地址
53         NSLog(@"str4 = %@", str4);           //输出修改后str4内容
54         NSLog(@"str4 address = %p", str4);     //输出修改后str4内容所在地址
55         NSLog(@"str5 = %@", str5);           //输出修改后str5内容
56         NSLog(@"str5 address = %p", str5);   //输出修改后str5内容所在地址
57         NSLog(@"str6 = %@", str6);             //输出修改后str6内容
58         NSLog(@"str6 address = %p", str6);     //输出修改后str6内容所在地址
59         NSLog(@"str7 = %@", str7);             //输出修改后str7内容
60         NSLog(@"str7 address = %p", str7);     //输出修改后str7内容所在地址
61
62     }
63     return 0;
64 }     
运行结果:

 1 2016-06-05 15:08:03.191 copyTest[1709:76858] @"a" address = 0x100001068
 2 2016-06-05 15:08:03.192 copyTest[1709:76858] change before:
 3 2016-06-05 15:08:03.192 copyTest[1709:76858] str1 = aaa
 4 2016-06-05 15:08:03.192 copyTest[1709:76858] str1 address = 0x1002001d0
 5 2016-06-05 15:08:03.192 copyTest[1709:76858] str2 = aaa
 6 2016-06-05 15:08:03.192 copyTest[1709:76858] str2 address = 0x1002001d0
 7 2016-06-05 15:08:03.192 copyTest[1709:76858] str3 = aaa
 8 2016-06-05 15:08:03.193 copyTest[1709:76858] str3 address = 0x1002002f0
 9 2016-06-05 15:08:03.193 copyTest[1709:76858] str4 = aaa
10 2016-06-05 15:08:03.193 copyTest[1709:76858] str4 address = 0x103000000
11 2016-06-05 15:08:03.193 copyTest[1709:76858] str5 = aaa
12 2016-06-05 15:08:03.193 copyTest[1709:76858] str5 address = 0x100200350
13 2016-06-05 15:08:03.193 copyTest[1709:76858] str6 = aaa
14 2016-06-05 15:08:03.193 copyTest[1709:76858] str6 address = 0x61616135
15 2016-06-05 15:08:03.193 copyTest[1709:76858] str7 = aaa
16 2016-06-05 15:08:03.193 copyTest[1709:76858] str7 address = 0x1002004c0
17 2016-06-05 15:08:03.193 copyTest[1709:76858]
18 2016-06-05 15:08:03.193 copyTest[1709:76858] @"bbb" address = 0x1000012a8
19 2016-06-05 15:08:03.193 copyTest[1709:76858] change after:
20 2016-06-05 15:08:03.193 copyTest[1709:76858] str1 = bbb
21 2016-06-05 15:08:03.193 copyTest[1709:76858] str1 address = 0x1002001d0
22 2016-06-05 15:08:03.193 copyTest[1709:76858] str2 = bbb
23 2016-06-05 15:08:03.193 copyTest[1709:76858] str2 address = 0x1002001d0
24 2016-06-05 15:08:03.193 copyTest[1709:76858] str3 = aaa
25 2016-06-05 15:08:03.194 copyTest[1709:76858] str3 address = 0x1002002f0
26 2016-06-05 15:08:03.194 copyTest[1709:76858] str4 = aaa
27 2016-06-05 15:08:03.194 copyTest[1709:76858] str4 address = 0x103000000
28 2016-06-05 15:08:03.194 copyTest[1709:76858] str5 = aaa
29 2016-06-05 15:08:03.194 copyTest[1709:76858] str5 address = 0x100200350
30 2016-06-05 15:08:03.194 copyTest[1709:76858] str6 = aaa
31 2016-06-05 15:08:03.194 copyTest[1709:76858] str6 address = 0x61616135
32 2016-06-05 15:08:03.194 copyTest[1709:76858] str7 = aaa
33 2016-06-05 15:08:03.194 copyTest[1709:76858] str7 address = 0x1002004c0
34 Program ended with exit code: 0

结果分析:

一、改变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不同,所以内容不会发生改变。

我们再做一个测试:

 1 //main.m
 2
 3 #import <Foundation/Foundation.h>
 4
 5 int main(int argc, const char * argv[]) {
 6     @autoreleasepool {
 7
 8         NSString *str1 = @"a";
 9         NSMutableString *str2;
10         NSMutableString *str3;
11
12         NSMutableString *str4 = [NSMutableString stringWithString:@"a"];
13         NSString *str5;
14         NSString *str6;
15
16         //一个不可变字符串str1使用copy和MutableCopy创建两个新副本给2个可变字符串str2和str3
17         str2 = [str1 copy];
18         str3 = [str1 mutableCopy];
19
20         //一个可变字符串str4使用copy和MutableCopy创建两个新副本给2个不可变字符串str5和str6
21         str5 = [str4 copy];
22         str6 = [str4 mutableCopy];
23
24         NSLog(@"str1 address = %p", str1);
25         NSLog(@"str2 address = %p", str2);
26         NSLog(@"str3 address = %p", str3);
27         NSLog(@"str4 address = %p", str4);
28         NSLog(@"str5 address = %p", str5);
29         NSLog(@"str6 address = %p", str6);
30
31     }
32     return 0;
33 }
1 //运行结果:
2
3 2016-06-05 16:57:01.697 copyTest[2175:117425] str1 address = 0x100001050
4 2016-06-05 16:57:01.698 copyTest[2175:117425] str2 address = 0x100001050
5 2016-06-05 16:57:01.698 copyTest[2175:117425] str3 address = 0x100203980
6 2016-06-05 16:57:01.698 copyTest[2175:117425] str4 address = 0x1002037b0
7 2016-06-05 16:57:01.698 copyTest[2175:117425] str5 address = 0x6115
8 2016-06-05 16:57:01.698 copyTest[2175:117425] str6 address = 0x100203a70
9 Program ended with exit code: 0

结果一目了然。不可变字符串的使用copy创建的新副本无论赋值给可变还是不可变字符串,都不会分配新的内存空间。

时间: 2024-10-16 08:32:16

探讨NSString和NSMutableString的内存问题以及copy和MutableCopy两个方法的相关文章

Foundation框架(NSString、NSMutableString)

OC字符串(NSString.NSMutableString) 概述:在Object C中存在两个类用于操作字符串,NSString和NSMutableString;NSString在赋值之后不能修改其内容和长度,而NSMutableString可以动态的修改字符串内容和长度. 一.NSString 1.NSString的多种定义方式 1)使用@符号快速创建一个字符串 NSString *str1 = @“jack”; 2)使用对象初始化方法 initWithString  NSString *

Foundation框架-NSString和NSMutableString

可变与不可变的字符串 --1-- Foundation框架介绍 1.1 框架介绍 --2-- NSString 2.1 NSString介绍及使用 2.2 NSString创建方式  2.3 从文件中读取/存储字符串 2.4 字符串的比较 2.5 前后缀检查及搜索 2.6 字符串的截取和替换 2.7 获取字符串的每个字符 2.8 字符串和其他数据类型转换 2.9 NSString去除空格  --3-- NSMutableString 3.1 NSMutableString 基本概念 3.2 字符

NSString 与NSMutableString的区别

  NSString 与NSMutableString的区别    Suppose You have a code like this NSString *s = [[NSString alloc] initWithString:@"Hello"]; s = [s stringByAppendingString:@"World"];   假如NSString是这样 and other code like this NSMutableString *ms = [[NS

关于NSString和NSMutableString的相关用法和基本介绍

Objective-C 中核心处理字符串的类是 NSString 与 NSMutableString ,这两个类最大的区别就是NSString 创建赋值以后该字符串的内容与长度不能在动态的更改,除非重新给这个字符串赋值.而NSMutableString 创建赋值以后可以动态在该字符串上更改内容与长度. NSString 常用方法总结 +(id)stringWithContentsOfFile:path encoding:enc err 创建一个新字符串并将其设置为 path 指定文件的内容,使用

iOS基础-NSString及NSMutableString剖析

一.NSString头文件 NSString : NSObject 实现协议: NSCopying/NSMutableCopying/NSSecureCoding 类别: //扩展类别 NSString (NSStringExtensionMethods) //此API是用来检测给定原始数据的字符串编码 NSString (NSStringEncodingDetection) NSMutableString : NSString 类别: //可以实现子类的原始replaceCharactersI

NSString 和 NSMutableString

// //  main.m //  字符串(NSString&NSMutableString) // //  Created by 闫合 on 16/5/19. //  Copyright © 2016年 闫合. All rights reserved. // #pragma mark NSString 和 NSMutableString #import <Foundation/Foundation.h> int main(int argc, const char * argv[])

NSString和NSMutableString常用方法+NSArray常用代码 (转)

常见的NSString和NSMutableString方法: NSString方法: [plain] view plaincopy +(id) stringWithContentsOfFile:path encoding:enc error:err 创建一个新字符串并将其设置为path指定的文件的内容,使用字符编码enc,如果非零,则返回err中错误 +(id) stringWithContentsOfURL:url encoding:enc error:err 创建一个新的字符串,并将其设置为

&lt;&lt;黑马程序员&gt;&gt;NSString 和 NSMutableString 的使用

NSString.NSMutableString基本用法 NSString其实是一个对象类型.NSString是NSObject的子类 一.NSString的创建 1.创建常量字符串.NSString *astring = @"This is a String!"; 2.创建空字符串,给予赋值.NSString *astring = [[NSString alloc] init];astring = @"This is a String!";[astring rel

黑马程序员-OC学习笔记之NSString与NSMutableString

---------------------- IOS开发.Android培训.期待与您交流! ---------------------- 一.NSString与NSMutableString 相信大家对NSString类都不陌生,它是OC中提供的字符串类,它的对象中的字符串都是不可变的,而它的子类NSMutableString类的对象中的字符串就是可变的.什么是可变与不可变呢?二者的区别就是在已经创建的一个字符串对象中,在程序中能不能更改字符串,比如拼接新的字符串,可变的可以在原字符串中更改,