小码哥-(知其所以然二)从底层分析OC中ARC和非ARC下深复制和浅...
来源:互联网 发布:东莞理工城市学院 网络 编辑:程序博客网 时间:2024/05/16 14:09
今天,在坊间听到有人在争论OC中关于NSString的深浅复制,听了下,感觉很有必要来一个分析总结,让我们从底层去了解OC中深浅复制的运作机制.
所谓copy就是在原有对象的基础上产生一个副本对象,遵循最关键的两点原则:
改变原对象的属性和行为不会对副本对象产生任何影响
改变副本对象的属性和行为不会对原对象产生任何影响
在理解了这一层之后,我们一起来研究下deep copy 和 shallow copy,因为苹果是一个非常注重性能的公司,所以拷贝在底层实现没那么简单:
以NSString为案例,以下四种情况彻底说明了什么是深复制和浅复制:
(一) 如果是不可变对象调用copy方法产出不可变副本,那么不会产生新的对象, 因此这是shallow copy,不会产生新的对象,指针地址相等.
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *srcStr = @"copy";
NSString *copyStr = [srcStr copy];
NSLog(@"%p %p", srcStr, copyStr);
}
return 0;
}
2014-05-25 22:26:13.805 03-复制[47093:303] 0x100001080 0x100001080
(二) 如果是不可变对象调用mutableCopy方法产出可变副本,那么一定会产生新的对象, 因此这是deep copy,会产生新的对象,指针地址不相等.
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *srcStr = @"copy";
NSMutableString *copyStr = [srcStr mutableCopy];
NSLog(@"srcStr=%p, copyStr=%p", srcStr, copyStr);
}
return 0;
}
2014-05-25 22:32:22.598 03-复制[47519:303] srcStr=0x100001080, copyStr=0x100203f70
(三) 如果是可变对象调用copy方法产出不可变副本,那么一定会产生新的对象, 因此这是deep copy,会产生新的对象,指针地址不相等.
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSMutableString *srcStr = [NSMutableString stringWithFormat:@"copy"];
NSString *copyStr = [srcStr copy];
NSLog(@"srcStr=%p, copyStr=%p", srcStr, copyStr);
}
return 0;
}
2014-05-25 22:35:37.218 03-复制[47754:303] srcStr=0x10010afd0, copyStr=0x1001031e0
(四) 如果是可变对象调用copy方法产出可变副本,那么一定会产生新的对象, 因此这是deep copy,会产生新的对象,指针地址不相等.
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSMutableString *srcStr = [NSMutableString stringWithFormat:@"copy"];
NSMutableString *copyStr = [srcStr mutableCopy];
NSLog(@"srcStr=%p, copyStr=%p", srcStr, copyStr);
}
return 0;
}
2014-05-25 22:37:40.300 03-复制[47897:303] srcStr=0x100203f70, copyStr=0x100204080
只有在第一种情况中才是浅复制,可以理解下复制的本意:虽然两对象内容相同,但绝对互不影响.为什么第一种是浅复制呢?因为是一个不可变的拷贝生产另外一个不可变的,既然都不可变,那干脆指向同一个内存空间.因为"苹果"很注重性能.
由于现在都在ARC下开发,非ARC下开发很少,但是还是来分析下其运作流程,以便巩固下知识:
两种情况,分别来分析:
(一) 在进行浅复制时,虽然没有产出新对象, 但是源对象和副本对象的计数器都会+1:
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *str = [NSString stringWithFormat:@"Copy"];
NSString *str2 = [str copy];
// [str2 release];
NSLog(@"%zd, %zd", [str retainCount], [str2 retainCount]);
}
return 0;
}
2014-05-25 22:48:28.151 04-复制和计数器[48639:303] 2, 2
为什么呢?这里牵扯到OC的内存管理原则了,凡事new,retain,copy..时,计数器都会+1,因为产生了一个新的对象,但是,如果是:
NSString *str = @"1"; // 一个常量 结果就是
2014-05-25 22:48:28.151 04-复制和计数器[48639:303] -1, -1
所有,在iOS中NSString是严格遵守NSCopying和NSMutableCopying的.
(二) 在进行深复制时,产出新对象, 但是源对象的计数器不变,副本对象的计数器+1:
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *str = @"Copy";
NSMutableString *str2 = [str mutableCopy];
NSLog(@"str=%zd, str2=%zd", [str retainCount], [str2 retainCount]);
// [str2 release];
}
return 0;
}
2014-05-25 22:59:08.688 04-复制[49397:303] str=-1, str2=1
运用copy的终极目的是: 当我赋值后,改变旧值不会影响新值. 如果要改变,就用retain..... 还有一点copy的底层实现,不就彻底弄清了:
- (void) setTitle : (NSString *)title{
if (_title != title){
[_title release];
_title = [title copy];
}
}
- (void)dealloc{
self.title = nil;
[super dealloc];
}
所谓copy就是在原有对象的基础上产生一个副本对象,遵循最关键的两点原则:
改变原对象的属性和行为不会对副本对象产生任何影响
改变副本对象的属性和行为不会对原对象产生任何影响
在理解了这一层之后,我们一起来研究下deep copy 和 shallow copy,因为苹果是一个非常注重性能的公司,所以拷贝在底层实现没那么简单:
以NSString为案例,以下四种情况彻底说明了什么是深复制和浅复制:
(一) 如果是不可变对象调用copy方法产出不可变副本,那么不会产生新的对象, 因此这是shallow copy,不会产生新的对象,指针地址相等.
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *srcStr = @"copy";
NSString *copyStr = [srcStr copy];
NSLog(@"%p %p", srcStr, copyStr);
}
return 0;
}
2014-05-25 22:26:13.805 03-复制[47093:303] 0x100001080 0x100001080
(二) 如果是不可变对象调用mutableCopy方法产出可变副本,那么一定会产生新的对象, 因此这是deep copy,会产生新的对象,指针地址不相等.
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *srcStr = @"copy";
NSMutableString *copyStr = [srcStr mutableCopy];
NSLog(@"srcStr=%p, copyStr=%p", srcStr, copyStr);
}
return 0;
}
2014-05-25 22:32:22.598 03-复制[47519:303] srcStr=0x100001080, copyStr=0x100203f70
(三) 如果是可变对象调用copy方法产出不可变副本,那么一定会产生新的对象, 因此这是deep copy,会产生新的对象,指针地址不相等.
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSMutableString *srcStr = [NSMutableString stringWithFormat:@"copy"];
NSString *copyStr = [srcStr copy];
NSLog(@"srcStr=%p, copyStr=%p", srcStr, copyStr);
}
return 0;
}
2014-05-25 22:35:37.218 03-复制[47754:303] srcStr=0x10010afd0, copyStr=0x1001031e0
(四) 如果是可变对象调用copy方法产出可变副本,那么一定会产生新的对象, 因此这是deep copy,会产生新的对象,指针地址不相等.
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSMutableString *srcStr = [NSMutableString stringWithFormat:@"copy"];
NSMutableString *copyStr = [srcStr mutableCopy];
NSLog(@"srcStr=%p, copyStr=%p", srcStr, copyStr);
}
return 0;
}
2014-05-25 22:37:40.300 03-复制[47897:303] srcStr=0x100203f70, copyStr=0x100204080
只有在第一种情况中才是浅复制,可以理解下复制的本意:虽然两对象内容相同,但绝对互不影响.为什么第一种是浅复制呢?因为是一个不可变的拷贝生产另外一个不可变的,既然都不可变,那干脆指向同一个内存空间.因为"苹果"很注重性能.
由于现在都在ARC下开发,非ARC下开发很少,但是还是来分析下其运作流程,以便巩固下知识:
两种情况,分别来分析:
(一) 在进行浅复制时,虽然没有产出新对象, 但是源对象和副本对象的计数器都会+1:
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *str = [NSString stringWithFormat:@"Copy"];
NSString *str2 = [str copy];
// [str2 release];
NSLog(@"%zd, %zd", [str retainCount], [str2 retainCount]);
}
return 0;
}
2014-05-25 22:48:28.151 04-复制和计数器[48639:303] 2, 2
为什么呢?这里牵扯到OC的内存管理原则了,凡事new,retain,copy..时,计数器都会+1,因为产生了一个新的对象,但是,如果是:
NSString *str = @"1"; // 一个常量 结果就是
2014-05-25 22:48:28.151 04-复制和计数器[48639:303] -1, -1
所有,在iOS中NSString是严格遵守NSCopying和NSMutableCopying的.
(二) 在进行深复制时,产出新对象, 但是源对象的计数器不变,副本对象的计数器+1:
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSString *str = @"Copy";
NSMutableString *str2 = [str mutableCopy];
NSLog(@"str=%zd, str2=%zd", [str retainCount], [str2 retainCount]);
// [str2 release];
}
return 0;
}
2014-05-25 22:59:08.688 04-复制[49397:303] str=-1, str2=1
运用copy的终极目的是: 当我赋值后,改变旧值不会影响新值. 如果要改变,就用retain..... 还有一点copy的底层实现,不就彻底弄清了:
- (void) setTitle : (NSString *)title{
if (_title != title){
[_title release];
_title = [title copy];
}
}
- (void)dealloc{
self.title = nil;
[super dealloc];
}
0 0
- 小码哥-(知其所以然二)从底层分析OC中ARC和非ARC下深复制和浅...
- 小码哥-(知其所以然一)OC中block的底层实现和具体运用
- iOS中ARC和非ARC混用
- ARC 和 非ARC 下 oc对象和core Foundation对象的转换
- ARC 和 非ARC 下 oc 对象 和 CF 对象的转换
- ARC和非ARC混编
- ARC和非ARC模式
- (iOS) ARC和非ARC
- ARC和非ARC混编
- arc和非arc混编
- ARC和非ARC区别
- ios开发下arc和非arc文件混编
- __block在arc和非arc下含义是否一样
- ARC和非ARC下使用Block属性的问题
- ARC和非ARC下使用Block属性的问题
- iOS 开发,工程中混合使用 ARC 和非ARC
- ios开发,工程中混合使用ARC和非ARC
- iOS 开发,工程中混合使用 ARC 和非ARC
- linux的命令操作
- 60秒倒计时
- Bootstrap3 排版-对齐
- 强大的Android图片下载缓存库——Picasso<一>
- 九大内置对象(1)
- 小码哥-(知其所以然二)从底层分析OC中ARC和非ARC下深复制和浅...
- hiho一下 第124周 查找附近POI- 四叉树
- 简单游戏服务器客服端搭建
- Office2013图标出现白板的解决办法
- hibernate中关于对count(*)的查询
- Quartz学习之Lesson9-SchedulerListeners
- Shiro(一):shiro简介
- 智慧北京:新闻list页面布局的实现
- 操作系统之——进程 (1)进程的描述与控制