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;
}