/*
程序设计目的:分析深拷贝、浅拷贝、retain的使用和区别
注:实验前请关闭ARC
*/
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"
int main(int argc,constchar * argv[])
{
@autoreleasepool {
//测试:
//浅拷贝:
NSLog(@"浅拷贝:");
NSString *str = [NSStringstringWithFormat:@"%@",@"copy"];
NSLog(@"str创建之后计数器的值:%li",[str retainCount]);
NSLog(@"str内存地址: %p",str);
NSString *string = [strcopy];
NSLog(@"str浅拷贝之后计数器的值: %li",[str retainCount]);
NSLog(@"string的内存地址: %p",string);
NSLog(@"string的计数器的值:%li",[string retainCount]);
//深拷贝:
NSLog(@"深拷贝:");
NSMutableString *str_1 = [NSMutableStringstringWithFormat:@"Deep Copy"];
NSLog(@"str_1创建之后计数器的值: %li",[str_1 retainCount]);
NSLog(@"str_1的内存地址:%p",str_1);
NSMutableString *string_1 = [str_1copy];
NSLog(@"str_1深拷贝之后计数器的值: %li",[str_1 retainCount]);
NSLog(@"string_1的内存地址: %p",string_1);
NSLog(@"string_1的计数器的值:%li",[string_1 retainCount]);
//retain:
NSLog(@"retain:");
NSString *str_r = [NSStringstringWithFormat:@"retain"];
NSLog(@"str_r创建之后计数器的值: %li",[str_r retainCount]);
NSLog(@"str_r的内存地址:%p",str_r);
NSString *string_r = [str_rretain];
NSLog(@"str_r retain之后计数器的值: %li",[str_r retainCount]);
NSLog(@"string_r的内存地址: %p",string_r);
NSLog(@"string_r的计数器的值:%li",[string_r retainCount]);
//测试结果:
/*
输出结果:
2014-11-16 16:12:15.922 Ram_control[1400:303]浅拷贝:
2014-11-16 16:12:15.924 Ram_control[1400:303] str创建之后计数器的值:1
2014-11-16 16:12:15.924 Ram_control[1400:303] str内存地址: 0x100200c10
2014-11-16 16:12:15.925 Ram_control[1400:303] str浅拷贝之后计数器的值: 2
2014-11-16 16:12:15.925 Ram_control[1400:303] string的内存地址: 0x100200c10
2014-11-16 16:12:15.925 Ram_control[1400:303] string的计数器的值:2
2014-11-16 16:12:15.926 Ram_control[1400:303]深拷贝:
2014-11-16 16:12:15.926 Ram_control[1400:303] str_1创建之后计数器的值: 1
2014-11-16 16:12:15.927 Ram_control[1400:303] str_1的内存地址:0x1005001d0
2014-11-16 16:12:15.927 Ram_control[1400:303] str_1深拷贝之后计数器的值: 1
2014-11-16 16:12:15.927 Ram_control[1400:303] string_1的内存地址: 0x100500180
2014-11-16 16:12:15.928 Ram_control[1400:303] string_1的计数器的值:1
2014-11-16 16:12:15.928 Ram_control[1400:303] retain:
2014-11-16 16:12:15.928 Ram_control[1400:303] str_r创建之后计数器的值: 1
2014-11-16 16:12:15.929 Ram_control[1400:303] str_r的内存地址:0x100300b80
2014-11-16 16:12:15.929 Ram_control[1400:303] str_r retain之后计数器的值: 2
2014-11-16 16:12:15.930 Ram_control[1400:303] string_r的内存地址: 0x100300b80
2014-11-16 16:12:15.931 Ram_control[1400:303] string_r的计数器的值:2
*/
/*
注:关于本博客中讨论内存管理的章节,都是在关闭ARC模式下运行的,否则程序报错。
浅拷贝总结:
浅拷贝是对不可变对象的“假”复制,
从上面的测试可以看出,浅拷贝只是简单的使新指针指向对象,“对象永远只有一个!”从结果可以看到拷贝前后,指针所指向的内存地址没有改变,还是原来那个对象(str所指向的对象)的地址。浅拷贝的结果仅仅是对象的引用计数器自增1而已.
深拷贝总结:
深拷贝是对可变对象的真复制,
从上面的结果看出,深拷贝是对对象的拷贝,结果中显示原来的对象(str_1所指向的对象)的引用计数的值拷贝前后没有增减,指针string_1所指向的内存地址也不再是原来的地址,而且string_1所指向的对象的引用计数也是1,所以深拷贝是重新创一个新对象,但是却保留原来对象的值(原来对象的值是“deepcopy”);
retain:结果和浅拷贝一样,仅仅是使得对象的引用计数器自增1.但是他们难道就没什么区别吗,有,
1.retain可以对可变对象和不可变对象同时操作(对可变对象操作却不可能实现和copy一样结果),所以接收返回值的类型需要与使用retain的对象保持一致。
2.就是下边要讲的自定义copy,自定义copy需要实现一些协议,有些赘余,而retain这没有这方面的要求,如果不是必须最好使用retain。
retain的使用在数组和字典中。当数组或字典把id对象存入是,就是retain的操作。
*/
//自定义拷贝:接收copy消息的对象不是OC的基本类型(例如:NSString,NSArray等)而是自己定义的类。
/*随便在一个自定义类中加入下面1.2.3.三段代码都可以实现自定义拷贝
1.在person类(这个类可以是任何一个自定义的类)的头文件中声明使用NSCopying协议,
@interface Person : NSObject<NSCopying>
{
NSString *_name;
}
2.在person类的.m文件中实现NSCopying协议,把需要的操作写在方法中:
-(id)copyWithZone:(NSZone *)zone{
Person *man = [[[self class] allocWithZone:zone] init];
//我们希望copy的内容(或者说希望的操作)都在这实现。
man.name = self.name;
return man;
}
3.在复写的dealloc中还要把copy的对象release,
-(oneway void)dealloc{
[_name release];
[super dealloc];
}
*/
Person *man = [PersonpersonWithName:@"Bieber"];
Person *woman = [mancopy];
NSLog(@"man:%@",man.name);
NSLog(@"woman:%@",woman.name);
/*结果:
2014-11-16 17:12:45.337 Ram_control[1586:303] man:Bieber
2014-11-16 17:12:45.337 Ram_control[1586:303] woman:Bieber
*/
}
return0;
}