本帖最后由 小叶子 于 2014-9-28 11:50 编辑
深复制和浅复制
个人见解,欢迎探讨,部分观点来自网上.
简单的来说就是,在有指针的情况下.浅拷贝只是增加了一个指针指向已经存在的内存(地址),而深拷贝就是增加一个指针并且申请一个新的内存(地址),使这个增加的指针指向这个新的内存.采用深拷贝的情况下,释放内存的时候就不会出现在浅拷贝时重复释放同一内存的错误!
乍看,不就是copy和ratain吗?
retain是浅拷贝,copy是深拷贝?不一定.
说到这儿,又要想起copy和mutabCop:
copy语法的目的:改变副本的时候,不会影响到源对象;
深拷贝:内容拷贝,会产生新的对象。新对象计数器置为1,源对象计数器不变。
浅拷贝:指针拷贝,不会产生新的对象。源对象计数器+1。 拷贝有下面两个方法实现拷贝:
- <blockquote>- (id)copy;
- - (id)mutableCopy;
复制代码
要实现copy,必须实现<NSCopying>协议
数组,字典,字符串都已经实现了<NSCopying>协议,以下以字符串为例,其他的同理:
1.不可变字符串调用copy实现拷(浅拷贝)
- NSString *string = [[NSString alloc] initWithFormat: @"abcde"];
- // copy产生的是不可变副本,由于源对象本身就不可变,所以为了性能着想,copy会直接返回源对象本身
- // 源对象计数器会+1
- // 在浅拷贝情况下,copy其实就相当于retain
- NSString *str = [string copy];
复制代码
2.不可变字符串调用mutableCopy实现拷贝,(深拷贝)
- NSString *string = [[NSString alloc] initWithFormat: @"abcd"];
- // 产生了一个新的对象,计数器为1。源对象的计数器不变。
- NSMutableString *str = [string mutableCopy];//此时存在两个对象// str:1和// string:1
- // str和string不是相同对象
- // NSLog(@"%i", str == string);//0
- [str appendString: @" abcd"];//修改str不影响string
- NSLog(@"string: %@", string);
- NSLog(@"str:%@", str);
复制代码
3.可变字符串调用copy实现拷贝(深拷贝)
- NSMutableString *string = [NSMutableString stringWithFormat : @"age is %i", 10];
- // 会产生一个新对象,str计数器为1
- NSString *str = [string copy];
复制代码
4.可变字符串的MutableCopy(深拷贝)
- NSMutableString *string = [NSMutableString stringWithFormat : @"age is %i", 10];
- // 会产生一个新对象,str计数器为1
- NSMutableString *str = [string mutableCopy];
- [str appendString: @"1234"];//修改新对象不影响原对象
- NSLog(@"str: %@", str);
- NSLog(@"string: %@", string);
复制代码
5.拷贝自定义对象,下面以Student对象为例 a.Student要实现copy,必须实现<NSCopying>协议
b.实现<NSCopying>协议的方法: - - (id)copyWithZone: (NSZone *)zone
复制代码
Student.h文件
____________________________________________________________________
- @interface Student : NSObject <NSCopying>
- // copy代表set方法会release旧对象、copy新对象
- // 修改外面的变量,并不会影响到内部的成员变量
- // 建议:NSString一般用copy策略,其他对象一般用retain
- @property (nonatomic, copy) NSString *name;
- + (id)studentWithName: (NSString *)name;
- @end
复制代码
Student.m文件
____________________________________________________________________
- #import "Student.h"
- @implementation Student
- + (id)studentWithName: (NSString *)name {
- // 这里最好写[self class]
- Student *stu = [[[[self class] alloc] init] autorelease];
- stu.name = name;
- return stu;
- }
- - (void)dealloc {
- [_name release];
- [super dealloc];
- }
- #pragma mark description方法内部不能打印self,不然会造成死循环
- - (NSString *)description {
- return [NSString stringWithFormat: @"[name=%@]", _name];
- }
- #pragma mark copying协议的方法
- // 这里创建的副本对象不要求释放
- - (id)copyWithZone: (NSZone *)zone {
- Student *copy = [[[self class] allocWithZone:zone] init];
- // 拷贝名字给副本对象
- copy.name = self.name;
- return copy;
- }
- @end
复制代码
拷贝student
____________________________________________________________________
拷贝Student
- <blockquote>
- Student *stu1 = [Student studentWithName: @"stu1"];
- Student *stu2 = [stu1 copy];
- stu2.name = @"stu2";
- NSLog(@"stu1: %@", stu1);
- NSLog(@"stu2: %@", stu2);
- [stu2 release];
复制代码
小结:
建议:NSString一般用copy策略,其他对象一般用retain;
只有一种情况是浅拷贝:不可变对象调用copy方法时,其他情况都为深拷贝;
|