copy设计的目的:改变副本的时候,不会影响到原来的对象
1、一个对象使用copy或者mutableCopy方法可以创建对象的副本
2、copy需要先实现NSCopying协议,创建的是不可改变副本(NSString、NSArray、NSDictionary)
mutableCopy 需要先创建NSMutableCopying协议,创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)
3、深复制:内容拷贝,源对象和副本指向的是同一个对象。源对象引用计数器不变,副本计数器设置为1
浅复制:指针复制,源对象和副本对象指向的二十同一个对象,对象的引用对象加1,其实相当于做了一次retain操作
只有不可变对象创建不可变副本(copy)才是浅复制,其它都是深复制
4、NSString、NSArray、NSDictionary三种OC对象默认都已经实现了cooppying和NSMutableCopying协议
5、自定义类添加复制功能:
如果想自定义copy,那么必须遵守NSCopying,并实现copyWithZone:方法
如果想自定义mutableCopy,那么就必须遵守NSMutableCopying,并实现mutableCopyZone:方法
例如copy:
建议用self class 代替类名
- (id)copyWithZone:(NSZone *)zone{
id copy = [[[self class] allocWithZone:zone] init];
//这儿开始做一些属性的初始化
return copy;
}
测试demo代码如下:
在这个demo中主要演示copy、mutableCopy,解说深拷贝、浅拷贝
以及自定义copy、mutableCopy的方法
Student.h文件
#import <Foundation/Foundation.h>
@interface Student : NSObject<NSCopying>
//copy代表set方法会release旧对象,copy新对象
//修改外面的变量,并不会影响到内部的成员变量
//建议:NSString一般用copy策略,其它对象一般用retain
//retain 和外边是同一个对象,外边该了,里面这个name属性也会改
@property (nonatomic, retain) NSString *name;
+ (id)studentWithName:(NSString *)name;
@end
Student.m文件:
#import "Student.h"
@implementation Student
/**
//@property (copy) :的意思如同下面这段setName方法
- (void)setName:(NSString *)name{
if(_name!=name){
[_name release];
_name = [name copy];
}
}
**/
+ (id)studentWithName:(NSString *)name{
//最好写slef class
Student *stu = [[[[self class] alloc] init] autorelease];
stu.name = name;
return stu;
}
#pragma mark coping协议的方法
//这里创建的副本对象不要求释放
- (id)copyWithZone:(NSZone *)zone{
Student *copy = [[[self class] allocWithZone:zone]init];
copy.name = self.name;
return copy;
}
//description 内部不能打印self不然会有死循环
- (NSString *)description{
return [NSString stringWithFormat:@"name=%@",_name];
}
- (void) dealloc{
NSLog(@"student %@ is destoryed", self);
[_name release];
[super dealloc];
}
@end
GoodStudent.h文件:
#import "Student.h"
@interface GoodStudent : Student
@property (nonatomic, assign) int age;
+ (id) goodStudentWithAge:(int) age name:(NSString *)name;
@end
GoodStudent.m文件:
#import "GoodStudent.h"
@implementation GoodStudent
+ (id)goodStudentWithAge:(int)age name:(NSString *)name{
GoodStudent *good = [GoodStudent studentWithName:name];
good.age = age;
return good ;
}
#pragma mark 重写父类的方法
- (id)copyWithZone:(NSZone *)zone{
//一定要调用父类的这个方法,因为父类帮我们copy了名字
GoodStudent *copy = [super copyWithZone:zone];
copy.age = self.age;
return copy;
}
- (NSString *)description{
return [NSString stringWithFormat:@"[name=%@, age=%i]",self.name, _age];
}
@end
main测试方法:
#import <Foundation/Foundation.h>
#import "Student.h"
#import "GoodStudent.h"
void stringMutableCopy(){
NSString *string = [[NSString alloc] initWithFormat:@"age is %i",10];
//产生一个新的对象,计数器为1,源对象的计数器不改变
NSMutableString *str = [string mutableCopy];
NSLog(@"string: %zi",[string retainCount]); //1
NSLog(@"str :%zi",[str retainCount]); //1
//str和string不是相同对象
NSLog(@"%i",str ==string);//0
[str release];
[string release];
}
/**
只有这一种情况是浅拷贝:指针拷贝,不会产生新的对象
**/
void stringCopy(){
NSString *string = [[NSString alloc] initWithFormat:@"age is %i",10];
//copy是不可变副本,由于源对象本身就不可变,所以为了性能着想,copy直接返回源对象本身
// 源对象计数器+1
NSString *str = [string copy];
NSLog(@"%zi",[string retainCount]); //2
NSLog(@"%zi",[str retainCount]); //2
//相同对象
NSLog(@"%i",str == string); //1
[str release];
[string release];
}
/**
只有一种情况浅拷贝:string-string
**/
//深拷贝
void mutableStringCopy(){
NSMutableString *string = [NSMutableString stringWithFormat:@"age is %i",10];
NSString *str = [string copy];
NSLog(@"%i",str == string); //0
}
//深拷贝
void mutableStringMutableCopy(){
NSMutableString *string = [NSMutableString stringWithFormat:@"age is %i",10];
NSMutableString *str = [string mutableCopy];
NSLog(@"%i",str == string ); //0
[str appendString:@"abc"];
NSLog(@"%@", str); //10abc
}
//stendent属性的copy
void studentNameCopy(){
Student *stu = [[[Student alloc]init] autorelease];
NSMutableString *string = [NSMutableString stringWithFormat:@"age is %i", 10];
stu.name = string;
[string appendString:@"abcd"];
NSLog(@"stu.name=%@",stu.name);
NSLog(@"string=%@",string);
}
//stendent对象的copy
void studentCopy(){
Student *stu1 = [Student studentWithName:@"stu1"];
Student *stu2 = [stu1 copy];
NSLog(@"stu1:%@",stu1.name);
NSLog(@"stu2:%@",stu2.name);
stu2.name = @"stu2";
NSLog(@"stu1:%@",stu1.name);
NSLog(@"stu2:%@",stu2.name);
NSLog(@"%i",stu1 == stu2);
[stu2 release];
}
//GoodStudent子类的copy
void goodStudent(){
GoodStudent *goodStu1= [GoodStudent goodStudentWithAge:20 name:@"goodStu1"];
NSLog(@"goodStu1:%@",goodStu1);
GoodStudent *goodStu2 = [goodStu1 copy];
NSLog(@"goodStu2:%@",goodStu2);
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSLog(@"----stringMutableCopy----");
stringMutableCopy();
NSLog(@"----stringcopy----");
stringCopy();
NSLog(@"----mutableStringCopy----");
mutableStringCopy();
NSLog(@"----mutableStringMutableCopy----");
mutableStringMutableCopy();
NSLog(@"----studentNameCopy----");
studentNameCopy();
NSLog(@"----studentCopy----");
studentCopy();
NSLog(@"----goodStudent----");
goodStudent();
}
return 0;
}