深拷贝和浅拷贝的区别堆区前后地址一样吗

【瞎搞iOS开发10】聊一聊copy、mutableCopy、深拷贝、浅拷贝 - 简书
【瞎搞iOS开发10】聊一聊copy、mutableCopy、深拷贝、浅拷贝
同学们先思考3 个问题:
怎么用一个粗暴的方法区分可变和不可变的NSString、NSArray、NSDictionary对象?
copy、mutableCopy、浅拷贝、深拷贝啥关系
[block copy]会是什么结果?
后文的很多结论本质上是错的,但是有参考价值,可以看看,我也懒得改了。在这得感谢的提醒,从NSCopying协议方向去思考Copy和MutableCopy,就容易理解后文出现的各种情况了,推荐大家看看这位大兄弟写的:,再继续看文章。
区分可变字符串和不可变字符串对象
在测试过程中出现2种不可变字符串类:
__NSCFConstantString和NSTaggedPointerString
1种不可变字符串类:
__NSCFString
最开始我用isKindOfClass:[NSMutableString class]来判断是不是可变,结果不对,又改成isKindOfClass:NSClassFromString:@"__NSCFString",还是不对,后来发现__NSCFConstantString继承了__NSCFString类。正常情况都是可变类型继承不可变类型,NSMutableString继承不可变类NSString,但类簇里面却有不可变类继承可变类,有点奇葩,所以只能通过代码测试了。
NSString * strTemp = @"KKKK";
NSString * str_copy = [strTemp copy];
NSMutableString * mut_copy = [strTemp mutableCopy];
NSLog(@"strTemp
: %p",strTemp);
NSLog(@"str_copy
: %p",str_copy);
NSLog(@"mut_copy
: %p",mut_copy);
NSMutableString * mutStr = [NSMutableString stringWithString:@"HHHH"];
str_copy = [mutStr copy];
mut_copy = [mutStr mutableCopy];
NSLog(@"mutStr
: %p",mutStr);
NSLog(@"str_copy
: %p",str_copy);
NSLog(@"mut_copy
: %p",mut_copy);
大致的意思是分别对不可变string和可变string进行copy和mutableCopy,打印的结果如下:
[控制台打印] strTemp
: 0x101b2d1d8
[控制台打印] str_copy
: 0x101b2d1d8
[控制台打印] mut_copy
[控制台打印] mutStr
[控制台打印] str_copy
[控制台打印] mut_copy
String_Copy.png
用表格把打印结果整理了下,可以看出后面三种情况得到的字符串都和原字符串内存地址不一致,只有 [不可变Str copy] 的内存地址 等于 原不可变Str的内存地址,也就可以用下面的逻辑判断字符串是否可变,简单粗暴我喜欢,下面继续试NSArray和NSDictionary。
if ([constantString copy] == constantString) {
可变字符串对象
不可变字符串对象
区分可变和不可变的NSArray、NSDictionary对象
同时对NSArray和NSDictionary利用copy和mutableCopy做了同样的测试,原始数据中有3个JKObj对象,同时以obj1为样本,在整个过程中对obj1的引用计数做了统计(未在代码中贴出)。
JKObj * obj1 = [JKObj new];
JKObj * obj2 = [JKObj new];
JKObj * obj3 = [JKObj new];
NSArray * array = @[obj1,obj2,obj3];
NSArray * array_copy = array.
NSMutableArray * array_mutCopy = array.mutableC
NSArray * mutArr_copy = array_mutCopy.
NSMutableArray * mutArr_mutCopy = array_mutCopy.mutableC
NSLog(@"%p
%@",array,array);
NSLog(@"%p
%@",array_copy,array_copy);
NSLog(@"%p
%@",array_mutCopy,array_mutCopy);
NSLog(@"%p
%@",mutArr_copy,mutArr_copy);
NSLog(@"%p
%@",mutArr_mutCopy,mutArr_mutCopy);
打印结果:
11:15:44.323 CopyAndMutableCopy[8] 0xc0
"&JKObj: 0x&",
"&JKObj: 0x&",
"&JKObj: 0xea0&"
11:15:44.323 CopyAndMutableCopy[8] 0xc0
"&JKObj: 0x&",
"&JKObj: 0x&",
"&JKObj: 0xea0&"
11:15:44.324 CopyAndMutableCopy[8] 0xa0
"&JKObj: 0x&",
"&JKObj: 0x&",
"&JKObj: 0xea0&"
11:15:44.370 CopyAndMutableCopy[8] 0xba0
"&JKObj: 0x&",
"&JKObj: 0x&",
"&JKObj: 0xea0&"
11:15:44.370 CopyAndMutableCopy[8] 0x
"&JKObj: 0x&",
"&JKObj: 0x&",
"&JKObj: 0xea0&"
统计结果发现先前的逻辑同样适用于NSArray对象的判断。
copy不可变数组会增加原不可变数组对象的引用计数,不会创建新的数组对象(新容器),即容器指针拷贝(浅拷贝)。
其他3种情况都会创建新的数组对象(新容器),增加数组内元素对象obj的引用计数,即内容拷贝(深拷贝)。每创建新的容器,会增加原数组内元素对象obj的引用计数一次。
所以对数组的copy和mutableCopy是直接作用于容器数组对象,间接实现对数组内元素的拷贝,这样也节省大量的内存。
Array_Copy.png
以同样的方法对NSDictionary对象做了测试,发现和NSArray的测试结果一致。
Dictionary_Copy.png
继续往下看...
根据前面的测试结果做了统计,如表图(简书竟然不支持HTML表格,只能上图了)
QQ截图33.png
以前我对指针拷贝和内容的理解比较混乱,尤其是把指针拷贝理解成拷贝元素的指针。进公司的笔试题就有深浅拷贝的题目,我简单写了指针拷贝、内容拷贝,老大当时没细问,可能他也只知道这个层面,哈哈。以后我面试,就得问细点,然后扯到MRC里面去。咱回到正轨,下面是我的总结,欢迎讨论、指正。
浅拷贝:指针拷贝,增加容器对象的引用计数,不增加容器内元素的引用计数。
深拷贝:内容拷贝,创建新的容器对象,开辟新内存,增加容器内元素的引用计数。
下面的几个结论有误,Copy/MutableCopy的结果取决于被copy对象怎么实现NSCopying协议,而Copy/MutableCopy本身不会决定结果,所以下面的结论是不严谨的。如果按正常的逻辑实现NSCopying协议,下面的结论也能成立。
copy:返回不可变对象。
copy不可变对象,浅拷贝,obj == [obj copy];
copy可变对象,深拷贝,obj != [obj copy];
mutableCopy:返回可变对象。
mutableCop不可变对象,深拷贝,obj != [obj mutableCopy];
mutableCop可变对象,深拷贝,obj != [obj mutableCopy];
copy不可变对象是浅拷贝 ,copy可变对象、mutableCopy可变或不可变对象是深拷贝。
可用 obj == [obj copy]来判断obj是可变对象还是不可变对象,block无可变概念,所以除外。if ([Obj copy] == Obj) {
不可变对象
首先Block有3种Class,分别是__NSGlobalBlock__、__NSStackBlock__、__NSMallocBlock__,主要的区别是3者存储区域不同,另外__NSGlobalBlock__不会引用任务外部变量,__NSStackBlock__会引用外部变量,__NSMallocBlock__由[__NSStackBlock__ copy]而来,所以也会引用外部变量。这里说的引用外部变量指的是在block里面直接应用Block外的变量对象,而不是引用传入block里面的参数对象。
void (^globalBlock)(void) = ^(){
NSLog(@".");
NSLog(@"globalBlock
: %@",globalBlock);
NSLog(@"[globalBlock copy]
: %@",[globalBlock copy]);
NSLog(@"[globalBlock mutableCopy] : %@",[globalBlock mutableCopy]);
[控制台打印] globalBlock
: &__NSGlobalBlock__: 0x104e50100&
[控制台打印] [globalBlock copy]
: &__NSGlobalBlock__: 0x104e50100&
[控制台打印] -[__NSGlobalBlock__ mutableCopyWithZone:]: unrecognized selector sent to instance 0x104e50100
UIView * testView = [[UIView alloc] initWithFrame:CGRectMake(100, 400, 50, 50)];
testView.backgroundColor = [UIColor orangeColor];
__weak void(^stackBlock)() = ^(){
testView.backgroundColor = [UIColor redColor];
void (^tempMallocBlock)() = [stackBlock copy]
void (^tempMallocBlock_copy)() = [tempMallocBlock copy];
NSLog(@"stackBlock
: %@",stackBlock);
NSLog(@"[stackBlock copy]
: %@",tempMallocBlock);
NSLog(@"[[stackBlock copy] copy] : %@",tempMallocBlock_copy);
[控制台打印] stackBlock
: &__NSStackBlock__: 0x7fff&
[控制台打印] [stackBlock copy]
: &__NSMallocBlock__: 0x&
[控制台打印] [[stackBlock copy] copy] : &__NSMallocBlock__: 0x&
Block的原始类型
newBlock = [Block copy]得到的newBlock类型
newBlock == [Block copy]
__NSGlobalBlock__
__NSGlobalBlock__
__NSStackBlock__
__NSMallocBlock__
__NSMallocBlock__
__NSMallocBlock__
值得注意的事stackBlock会强引用外部对象,在[stackBlock copy]产生的mallocBlock也会强引用外部对象,所以在这个过程中,外部变量的引用计数会被增加2次。如果外部变量强引用Block,又被Block强引用,就会产生循环引用,这时候可以用weak-strong转换的方法解决。或者将外部对象通过传参传入block,block只会在执行过程中retain参数对象,增加参数对象的引用计数,执行完就会release,解除强引用。第一种方法比较常用,第二种方法适用范围较小,如果block是在其他类执行,代码就可能不太好理解。
最近的文章代码有点乱,文字解说的少,有疑惑的可以提出来,望大神们多多指点。
【瞎搞iOS开发09】里面对block做了比较详细的测试,有兴趣可以看看。
路在脚下,梦在远方。
----iOS开发菜鸟安全检查中...
请打开浏览器的javascript,然后刷新浏览器
< 浏览器安全检查中...
还剩 5 秒&C/C++(102)
& & 类定义中,如果未提供自己的拷贝构造函数,则C&#43;&#43;提供一个默认拷贝构造函数,就像没有提供构造函数时,C&#43;&#43;提供默认构造函数一样。
& & C&#43;&#43;提供的默认拷贝构造函数工作的方法是:完成一个成员一个成员的拷贝,如果成员是类对象,则调用其拷贝构造函数或者默认拷贝构造函数。
& & 在默认拷贝构造函数中,拷贝的策略是逐个成员依次拷贝,但是,一个类可能会拥有资源,如果拷贝构造函数简单地制作了一个该资源的拷贝,而不对它本身分配,就得面临一个麻烦的局面:两个对象都拥有同一个资源。当对象析构时,该资源将经历两次资源返还。
& & 下面的程序描述了Person对象被简单拷贝后,面临析构时的困惑。
class Person
Person(char *pN)
cout &&&Constructing &&&pn&&
char (strlen(pN)+1);
if (pName!=0)
strcpy(pName,pN);
cout&&&Destructing &&&pname&&
pName[0]=&#39;\0&#39;;
protected:
int main()
p1(&Randy&);
//即Person
result is :
Constructing Randy
Destructing Randy
Destructing&
& & 程序开始运行时,创建p1对象,p1对象的构造函数从堆中分配空间并赋给数据成员pName,执行,p2=p1时,因为没有定义拷贝构造函数,于是就调用默认拷贝构造函数,使得p2与p1完全一样,并没有新分配堆空间给p2,&
p1与p2的pName都是同一个&#20540;。析构p2时,将堆中字符串清成空串,然后将堆空间返还给系统; 析构p1时,因为这是pName指向的是空串,所以第三行输出中显示的只是Destructing,当执行 delete pN 按道理系统应该报错,但在gcc中没有。
& & 创建p2时,对象p1被复制了p2,但资源并未复制,因此,p1和p2指向同一个资源,这称为浅拷贝。当一个对象创建时,分配了资源,这时,就需要定义自己的拷贝构造函数,使之不但拷贝成员,也拷贝资源。
class Person
Person(char *pN)
cout &&&Constructing &&&pn&&
char (strlen(pN)+1);
if (pName!=0)
strcpy(pName,pN);
Person(Person& p)
cout &&&copying &&&p.pname&&&into its=&& own=&& block\n&;
pName=new char [sizeof(p.pName)];
if (pName!=0)
strcpy(pName,p.pName);
cout&&&Destructing &&&pname&&
pName[0]=&#39;\0&#39;;
protected:
int main()
p1(&Randy&);
//即Person
}result is :
Constructing Randy
copying Randyinto its own block
Destructing Randy
Destructing Randy
& & 创建p2时,对象p1被复制给了p2,同时资源也作了复制,因此p1和p2指向不同的资源,这称为深拷贝。堆内存并不是唯一需要拷贝构造函数的资源,但它是最常用的一个。打开文件,占有硬设备(例如打印机)服务也需要深拷贝。他们也是析构函数必须返还的资源类型。因此一个很好的经验是:
& &如果你的类需要析构函数来析构资源,则它也需要一个拷贝构造函数。
& & 因为通常对象是自动被析构的,如果需要一个自定义的析构函数,那就意味着有额外资源要在对象被析构之前释放,此时,对象的拷贝就不是浅拷贝了。
& & 注:经查资料,上面这句话应该是这样才更全面
& &&如果需要析构函数,则一定需要拷贝构造函数和赋&#20540;操作符。
详细解释说明见下文:
(强烈推荐)
今天在看一个消息结构的定义类时,有一个这样的接口
WF_MSG & operator=(const WF_MSG & _msg);
开始不是很明白,后来才知道这是赋&#20540;操作符,也通过这个深刻了解了赋&#20540;操作符,因为还定义了一个unsigned char * m_pMsgB /// 消息缓存指针 的指针,一般默认的赋&#20540;操作符是浅拷贝,而因为有消息缓存指针的变量,当这个消息类有两个对象时,如果一个消息赋&#20540;给另外一个消息,则会涉及到深拷贝的问题,所以要重新定义赋&#20540;操作符
这里有一博客,叙述的很详细,给大家分享下:
赋&#20540;运算符和复制构造函数都是用已存在的B对象来创建另一个对象A。不同之处在于:赋&#20540;运算符处理两个已有对象,即赋&#20540;前B应该是存在的;复制构造函数是生成一个全新的对象,即调用复制构造函数之前A不存在。
CTemp a(b); //复制构造函数,C&#43;&#43;风&#26684;的初始化
CTemp a=b; //仍然是复制构造函数,不过这种风&#26684;只是为了与C兼容,与上面的效果一样
在这之前a不存在,或者说还未构造好。
a=b; //赋&#20540;运算符
在这之前a已经通过默认构造函数构造完成。
实例总结:
包含动态分配成员的类 应提供拷贝构造函数,并重载&=&赋&#20540;操作符。
以下讨论中将用到的例子:
class CExample
CExample(){pBuffer=NULL; nSize=0;}
~CExample(){delete pB}
void Init(int n){ pBuffer=new char[n]; nSize=n;}
char *pB //类的对象中包含指针,指向动态分配的内存资源
这个类的主要特点是包含指向其他资源的指针。
pBuffer指向堆中分配的一段内存空间。
一、拷贝构造函数
调用拷贝构造函数1
int main(int argc, char* argv[])
CExample theO
theObjone.Init(40);
//现在需要另一个对象,需要将他初始化称对象一的状态
CExample theObjtwo=theO//拷贝构造函数
语句&CExample theObjtwo=theO&用theObjone初始化theObjtwo。
其完成方式是内存拷贝,复制所有成员的&#20540;。
完成后,theObjtwo.pBuffer==theObjone.pBuffer。
即它们将指向同样的地方(地址空间),指针虽然复制了,但所指向的空间内容并没有复制,而是由两个对象共用了。这样不符合要求,对象之间不独立了,并为空间的删除带来隐患。
所以需要采用必要的手段来避免此类情况。
回顾以下此语句的具体过程:通过拷贝构造函数(系统默认的)创建新对象theObjtwo,并没有调用theObjtwo的构造函数(vs2005试验过)。
可以在自定义的拷贝构造函数中添加输出的语句测试。
对于含有在自由空间分配的成员时,要使用深度复制,不应使用浅复制。
调用拷贝构造函数2
当对象直接作为参数传给函数时,函数将建立对象的临时拷贝,这个拷贝过程也将调同拷贝构造函数。
BOOL testfunc(CExample obj);
testfunc(theObjone); //对象直接作为参数。
BOOL testfunc(CExample obj)
//针对obj的操作实际上是针对复制后的临时拷贝进行的
调用拷贝构造函数3
当函数中的局部对象被被返回给函数调者时,也将建立此局部对象的一个临时拷贝,拷贝构造函数也将被调用
CTest func()
CTest theT
return theTest
二、赋&#20540;符的重载
下面的代码与上例相&#20284;
int main(int argc, char* argv[])
CExample theO
theObjone.Init(40);
CExample theO
theObjthree.Init(60);
//现在需要一个对象赋&#20540;操作,被赋&#20540;对象的原内容被清除,并用右边对象的内容填充。
theObjthree=theO
也用到了&=&号,但与&一、&中的例子并不同,&一、&的例子中,&=&在对象声明语句中,表示初始化。更多时候,这种初始化也可用括号表示。
例如 CExample theObjone(theObjtwo);
而本例子中,&=&表示赋&#20540;操作。将对象theObjone的内容复制到对象theO,这其中涉及到对象theObjthree原有内容的丢弃,新内容的复制。
但&=&的缺省操作只是将成员变量的&#20540;相应复制。旧的&#20540;被自然丢弃。
由于对象内包含指针,将造成不良后果:为了避免内存泄露,指针成员将释放指针所指向的空间,以便接受新的指针&#20540;,这正是由赋&#20540;运算符的特征所决定的。但如果是&x=x&即自己给自己赋&#20540;,会出现什么情况呢?x将释放分配给自己的内存,然后,从赋&#20540;运算符右边指向的内存中复制&#20540;时,发现&#20540;不见了。
因此,包含动态分配成员的类除提供拷贝构造函数外,还应该考虑重载&=&赋&#20540;操作符号。
类定义变为:
class CExample
CExample(const CExample&); //拷贝构造函数
CExample& operator = (const CExample&); //赋&#20540;符重载
//赋&#20540;操作符重载
CExample & CExample::operator = (const CExample& RightSides)
nSize=RightSides.nS //复制常规成员
char *temp=new char[nSize]; //复制指针指向的内容
memcpy(temp, RightSides.pBuffer, nSize*sizeof(char));
delete []pB //删除原指针指向内容 (将删除操作放在后面,避免X=X特殊情况下,内容的丢失)
pBuffer= //建立新指向
return *this
三、拷贝构造函数使用赋&#20540;运算符重载的代码。
CExample::CExample(const CExample& RightSides)
pBuffer=NULL;
*this=RightSides //调用重载后的&=&
==========================
赋&#20540;运算符(operator=)和复制构造函数:A(A& a){}都是用已存在A的对象来创建另一个对象B。不同之处在于:赋&#20540;运算符处理两个已有对象,即赋&#20540;前B应该是存在的;复制构造函数是生成一个全新的对象,即调用复制构造函数之前B不存在。&&&
&&&&&& CTemp B(A);&&&&&& //复制构造函数,C&#43;&#43;风&#26684;的初始化
&&&&&& CTemp B=A;&&&&&& //仍然是复制构造函数,不过这种风&#26684;只是为了与C兼容,与上面的效果一样
&&&&&& 在这之前B不存在,或者说还未构造好。
&&&&&& CTemp B;
&&&&&& B = A;&&&&&&&&&&&&&&& //赋&#20540;运算符
&&&&&& 在这之前B已经通过默认构造函数构造完成。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:631740次
积分:6852
积分:6852
排名:第3386名
原创:96篇
转载:240篇
评论:79条
(3)(8)(3)(4)(4)(10)(4)(5)(8)(5)(3)(1)(4)(4)(3)(8)(2)(1)(3)(4)(4)(3)(6)(5)(5)(5)(7)(4)(4)(6)(1)(9)(2)(6)(14)(10)(3)(1)(2)(6)(2)(5)(8)(7)(8)(14)(20)(13)(4)(11)(11)(13)(2)(20)(8)copy与retain的区别:
1)copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化。
copy与retain的区别:
1)copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。
2)retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝。
#pragma mark - iOS系统的集合类与非集合类的retain和copy
NSString *str1 = [[NSString alloc] initWithFormat:@"%@", @"Jacedy"];
NSString *str11 = [str1 retain];
NSString *str12 = [str1 copy];
NSString *str13 = [str1 mutableCopy];
NSMutableString *str2 = [[NSMutableString alloc] initWithString:@"Jake"];
NSMutableString *str21 = [str2 retain];
NSMutableString *str22 = [str2 copy];
NSMutableString *str23 = [str2 mutableCopy];
NSLog(@"非容器类");
NSLog(@"str1 的地址:%p,retainCount:%lu", str1, (unsigned long)[str1 retainCount]);
NSLog(@"str11的地址:%p,retainCount:%lu", str11, (unsigned long)[str11 retainCount]);
NSLog(@"str12的地址:%p,retainCount:%lu", str12, (unsigned long)[str12 retainCount]);
NSLog(@"str13的地址:%p,retainCount:%lu\n\n", str13, (unsigned long)[str13 retainCount]);
NSLog(@"str2 的地址:%p,retainCount:%lu", str2, (unsigned long)[str2 retainCount]);
NSLog(@"str21的地址:%p,retainCount:%lu", str21, (unsigned long)[str21 retainCount]);
NSLog(@"str22的地址:%p,retainCount:%lu", str22, (unsigned long)[str22 retainCount]);
NSLog(@"str23的地址:%p,retainCount:%lu\n\n", str23, (unsigned long)[str23 retainCount]);
NSArray *arr1 = [NSArray arrayWithObjects:@"one", @"two", nil];
NSArray *arr11 = [arr1 retain];
NSArray *arr12 = [arr1 copy];
NSArray *arr13 = [arr1 mutableCopy];
NSMutableArray *arr2 = [NSMutableArray arrayWithObjects:@"one", @"two", nil];
NSMutableArray *arr21 = [arr2 retain];
NSMutableArray *arr22 = [arr2 copy];
NSMutableArray *arr23 = [arr2 mutableCopy];
NSLog(@"容器类");
NSLog(@"arr1 的地址:%p,retainCount:%lu", arr1, (unsigned long)[arr1 retainCount]);
NSLog(@"arr11的地址:%p,retainCount:%lu", arr11, (unsigned long)[arr11 retainCount]);
NSLog(@"arr12的地址:%p,retainCount:%lu", arr12, (unsigned long)[arr12 retainCount]);
NSLog(@"arr13的地址:%p,retainCount:%lu", arr13, (unsigned long)[arr13 retainCount]);
NSLog(@"arr1[0] :%p", arr1[0]);
NSLog(@"arr13[0]:%p\n\n", arr13[0]);
NSLog(@"arr2 的地址:%p,retainCount:%lu", arr2, (unsigned long)[arr2 retainCount]);
NSLog(@"arr21的地址:%p,retainCount:%lu", arr21, (unsigned long)[arr21 retainCount]);
NSLog(@"arr22的地址:%p,retainCount:%lu", arr22, (unsigned long)[arr22 retainCount]);
NSLog(@"arr23的地址:%p,retainCount:%lu", arr23, (unsigned long)[arr23 retainCount]);
NSLog(@"arr2[0] :%p", arr2[0]);
NSLog(@"arr22[0]:%p\n\n", arr22[0]);
#pragma mark - NSString 内存管理
NSString *string1 = @"Jacedy";
NSString *string2 = [[NSString alloc] initWithString:@"KJacedy"];
NSString *string3 = [[NSString alloc] initWithFormat:@"Jacedy"];
NSString *string4 = [NSString stringWithFormat:@"K-Jacedy"];
NSLog(@"NSString内存管理");
NSLog(@"string1:%p retainCount:%lu
class:%@", string1, [string1 retainCount], [string1 class]);
NSLog(@"string2:%p retainCount:%lu
class:%@", string2, [string2 retainCount], [string2 class]);
NSLog(@"string3:%p retainCount:%lu
class:%@", string3, [string3 retainCount], [string3 class]);
NSLog(@"string4:%p retainCount:%lu
class:%@\n\n", string4, [string4 retainCount], [string4 class]);
str1 的地址:0xa65,retainCount:
str11的地址:0xa65,retainCount:
str12的地址:0xa65,retainCount:
str13的地址:0x,retainCount:1
str2 的地址:0x,retainCount:2
str21的地址:0x,retainCount:2
str22的地址:0x656b614a45,retainCount:
str23的地址:0x,retainCount:1
arr1 的地址:0x,retainCount:3
arr11的地址:0x,retainCount:3
arr12的地址:0x,retainCount:3
arr13的地址:0x,retainCount:1
arr1[0] :0x
arr13[0]:0x
arr2 的地址:0x,retainCount:2
arr21的地址:0x,retainCount:2
arr22的地址:0x,retainCount:1
arr23的地址:0x,retainCount:1
arr2[0] :0x
arr22[0]:0x
NSString内存管理
string1:0x retainCount:
class:__NSCFConstantString
string2:0x retainCount:
class:__NSCFConstantString
string3:0xa65 retainCount:
class:NSTaggedPointerString
string4:0xd2eec retainCount:
class:NSTaggedPointerString
Program ended with exit code: 0
深拷贝与浅拷贝结论:
1)对非集合类:
[immutableObject copy] // 浅复制
[immutableObject mutableCopy] //深复制
[mutableObject copy] //深复制
[mutableObject mutableCopy] //深复制
2)对集合类:
[immutableObject copy] // 浅复制
[immutableObject mutableCopy] //单层深复制(即仅对对象本身进行深复制,对象元素仍是浅复制(指针拷贝,内存地址不变))
[mutableObject copy] //单层深复制
[mutableObject mutableCopy] //单层深复制
NSString内存分配结论:
@“” 和 initWithString:方法生成的字符串分配在常量区,系统自动管理内存;
initWithFormat:和 stringWithFormat: 方法生成的字符串分配在堆区,autorelease
版权声明:本文内容由互联网用户自发贡献,本社区不拥有所有权,也不承担相关法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至: 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
用云栖社区APP,舒服~
【云栖快讯】集合阿里巴巴、阿里云技术干货!历届云栖社区在线峰会技术荟萃专题出炉,赶紧收藏吧~&&
一种高性能、高可靠、可平滑扩容的分布式内存数据库服务。
一个稳定可靠的集中式访问控制服务。您可以通过访问控制将阿里云资源的访问及管理权限分配给您的企业成员或合作伙伴。
阿里云移动APP解决方案,助力开发者轻松应对移动app中随时可能出现的用户数量的爆发式增长、复杂的移动安全挑战等...
为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本...
2017杭州云栖大会火热抢票
Loading...}

我要回帖

更多关于 深拷贝和浅拷贝的区别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信