Open yidaizhenlong opened 11 years ago
首先先了解copy与retain的区别,如果有不正确的地方望大家多多指教: copy与retain的区别: copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。 retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝。 //1. 系统的非容器类对象,这里指的是NSString,NSNumber等等一类的对象。 NSString testString=@"testString"; NSString copyString=[testString copy]; NSMutableString stringMutableCopy = [testString mutableCopy]; [stringMutableCopy appendString:@" mutableCopy"]; ////查看内存可以发现,testString和copyString指向的是同一块内存区域(又叫apple弱引用weak reference),而stringMutableCopy则是我们所说的真正意义上的复制,系统为其分配了新内存,但指针所指向的字符串还是和testString所指的一样。 NSMutableString mutablString = [NSMutableString stringWithString: @"origion"]; NSString mutablStringCopy = [mutablString copy]; NSMutableString mStringCopy = [mutablString copy]; NSMutableString mStringMCopy = [mutablString mutableCopy]; [mStringCopy appendString:@"mStringCopy"];//error [mutablString appendString:@"mutablString!"]; [mStringMCopy appendString:@"mStringMCopy"]; [mutablStringCopy appendString:@"mutablStringCopy"] ; // 以上四个NSString对象所分配的内存都是不一样的。但是对于mStringCopy其实是个imutable对象,所以上述会报错。对于系统的非容器类对象,我们可以认为,如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。 //2 系统的容器类对象指NSArray,NSDictionary等。对于容器类本身,上面讨论的结论也是适用的,需要探讨的是复制后容器内对象的变化。 NSArray array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil]; NSArray arrayCopy1 = [array1 copy]; NSLog(@"array1 retain count: %ld",[array1 retainCount]); NSLog(@"array1 retain count: %ld",[arrayCopy1 retainCount]); NSMutableArray mArrayCopy1 = [array1 mutableCopy]; //mArrayCopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的是同一个对象。mArrayCopy1还可以修改自己的对象 [mArrayCopy1 addObject:@"de"]; [mArrayCopy1 removeObjectAtIndex:0]; NSLog(@"%@",mArrayCopy1);
//通过内存截图可以看出,array1和arrayCopy1是指针复制,而mArrayCopy1是对象复制,mArrayCopy1还可以改变期内的元素:删除或添加。但是注意的是,容器内的元素内容都是指针复制。截图可以证明 NSArray mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil]; NSArray mArrayCopy2 = [mArray1 copy]; NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy]; NSLog(@"chnge befor-----mArray1%@ mArrayMCopy1%@ %@",mArray1,mArrayMCopy1,mArrayCopy2);
NSMutableString *mTestString = [mArray1 objectAtIndex:0]; [mTestString appendString:@" change"]; NSLog(@"change after---- mArray1%@ mArrayMCopy1%@ %@",mArray1,mArrayMCopy1,mArrayCopy2);
//打印后发现,[mArray1 objectAtIndex:0]这个对象已经改变了,由此可见,对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷呗http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/ NSMutableArray array=[[NSMutableArray alloc] initWithObjects:@"a",@"b", nil]; NSMutableArray *deepCopyArray=[[NSMutableArray alloc] initWithArray: array copyItems: YES]; NSMutableArray trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject: array]];
[[trueDeepCopyArray objectAtIndex:0] appendString:@"trueDeepCopyArray"];
//trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的不可变元素其还是指针复制。或者我们自己实现深拷贝的方法。因为如果容器的某一元素是不可变的,那你复制完后该对象仍旧是不能改变的,因此只需要指针复制即可。除非你对容器内的元素重新赋值,否则指针复制即已足够。 心得:copy方法,得到的是不可变对象,不管以前的是可变还是不可变。mutableCopy方法,得到的是可变对象,不管以前的是可变还是不可变。 当我们要实现一个自定义的类的时候就要遵循NSCopying,或者NSMutableCopying的协议才行 @interface Person : NSObject<NSCopying,NSMutableCopying> @property (nonatomic,assign)NSMutableString name; @property (nonatomic,assign)NSString sex; @property (nonatomic,assign)NSString age; @property (nonatomic,assign)NSMutableString height;
(id) mutableCopyWithZone:(NSZone *)zone { NSLog(@"%d",zone);
NSLog(@"可变"); Person *mutableCopyPerson=[[Person allocWithZone:zone] init]; mutableCopyPerson.name=[self.name mutableCopy]; mutableCopyPerson.sex=[self.sex copy]; mutableCopyPerson.height=[self.height mutableCopy ]; mutableCopyPerson.age=[self.age mutableCopy];
return mutableCopyPerson; } Person _person=[[Person alloc] init]; _person.name=[NSMutableString stringWithString:@"唐余猛"]; _person.sex=@"男"; _person.height=[NSMutableString stringWithString:@"171"]; _person.age=@"24"; Person copyPerson=[_person copy];//走的copyWithZone方法 Person *mutableCopy=[_person mutableCopy];//走的是mutableCopyWithZone方法
这时候疑问就来了,我设置一个可变的自定义类,内部的属性设置成不可变呢?答案很简单,mutableCopyWithZone和copyWithZone只会对这个对象拷贝,不会对这个对象的属性拷贝。那么这样的话mutableCopyWithZone,和copyWithZone用起来对一个自定义对象有什么区别呢。 这个是属于你对这个类的设计目标,比如你要设计一个Person类,如果不需要外界来修改它,那就是不可变的, 如果需要外界修改它,那就建个MutablePerson, 并加上相应的修改数据成员的方法, 这完全取决你的设计。 但是事实上,我们自己写代码时,很少遵循这种可变,不可变类的这种模式,通常都是建一个类,提供相应的设置方法。 事实上,只有CocoaTouch, string, dictionary, array这些基础的数据类型,才按这种模式来,一般的Model 类,基本不这么弄, 按这种模式来,写起来也麻烦,每种规则并不一是一定的。 对于自定义的类,如果我们想要实现copy的语义,我们需要实现NSCopying, NSMutableCopying这2个protocol。 如果有不对的地方希望大家指出来
copyPerson.height=[self.height copy ]; copyPerson.age=[self.age copy]; 这个是会报错的。
首先先了解copy与retain的区别,如果有不正确的地方望大家多多指教: copy与retain的区别: copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。 retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝。 //1. 系统的非容器类对象,这里指的是NSString,NSNumber等等一类的对象。 NSString testString=@"testString"; NSString copyString=[testString copy]; NSMutableString stringMutableCopy = [testString mutableCopy]; [stringMutableCopy appendString:@" mutableCopy"]; ////查看内存可以发现,testString和copyString指向的是同一块内存区域(又叫apple弱引用weak reference),而stringMutableCopy则是我们所说的真正意义上的复制,系统为其分配了新内存,但指针所指向的字符串还是和testString所指的一样。 NSMutableString mutablString = [NSMutableString stringWithString: @"origion"]; NSString mutablStringCopy = [mutablString copy]; NSMutableString mStringCopy = [mutablString copy]; NSMutableString mStringMCopy = [mutablString mutableCopy]; [mStringCopy appendString:@"mStringCopy"];//error [mutablString appendString:@"mutablString!"]; [mStringMCopy appendString:@"mStringMCopy"]; [mutablStringCopy appendString:@"mutablStringCopy"] ; // 以上四个NSString对象所分配的内存都是不一样的。但是对于mStringCopy其实是个imutable对象,所以上述会报错。对于系统的非容器类对象,我们可以认为,如果对一不可变对象复制,copy是指针复制(浅拷贝)和mutableCopy就是对象复制(深拷贝)。如果是对可变对象复制,都是深拷贝,但是copy返回的对象是不可变的。 //2 系统的容器类对象指NSArray,NSDictionary等。对于容器类本身,上面讨论的结论也是适用的,需要探讨的是复制后容器内对象的变化。 NSArray array1 = [NSArray arrayWithObjects:@"a",@"b",@"c",nil]; NSArray arrayCopy1 = [array1 copy]; NSLog(@"array1 retain count: %ld",[array1 retainCount]); NSLog(@"array1 retain count: %ld",[arrayCopy1 retainCount]); NSMutableArray mArrayCopy1 = [array1 mutableCopy]; //mArrayCopy1是array1的可变副本,指向的对象和array1不同,但是其中的元素和array1中的元素指向的是同一个对象。mArrayCopy1还可以修改自己的对象 [mArrayCopy1 addObject:@"de"]; [mArrayCopy1 removeObjectAtIndex:0]; NSLog(@"%@",mArrayCopy1);
//通过内存截图可以看出,array1和arrayCopy1是指针复制,而mArrayCopy1是对象复制,mArrayCopy1还可以改变期内的元素:删除或添加。但是注意的是,容器内的元素内容都是指针复制。截图可以证明 NSArray mArray1 = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil]; NSArray mArrayCopy2 = [mArray1 copy]; NSMutableArray *mArrayMCopy1 = [mArray1 mutableCopy]; NSLog(@"chnge befor-----mArray1%@ mArrayMCopy1%@ %@",mArray1,mArrayMCopy1,mArrayCopy2);
//打印后发现,[mArray1 objectAtIndex:0]这个对象已经改变了,由此可见,对于容器而言,其元素对象始终是指针复制。如果需要元素对象也是对象复制,就需要实现深拷呗http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Articles/ NSMutableArray array=[[NSMutableArray alloc] initWithObjects:@"a",@"b", nil]; NSMutableArray *deepCopyArray=[[NSMutableArray alloc] initWithArray: array copyItems: YES]; NSMutableArray trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject: array]];
//trueDeepCopyArray是完全意义上的深拷贝,而deepCopyArray则不是,对于deepCopyArray内的不可变元素其还是指针复制。或者我们自己实现深拷贝的方法。因为如果容器的某一元素是不可变的,那你复制完后该对象仍旧是不能改变的,因此只需要指针复制即可。除非你对容器内的元素重新赋值,否则指针复制即已足够。 心得:copy方法,得到的是不可变对象,不管以前的是可变还是不可变。mutableCopy方法,得到的是可变对象,不管以前的是可变还是不可变。 当我们要实现一个自定义的类的时候就要遵循NSCopying,或者NSMutableCopying的协议才行 @interface Person : NSObject<NSCopying,NSMutableCopying> @property (nonatomic,assign)NSMutableString name; @property (nonatomic,assign)NSString sex; @property (nonatomic,assign)NSString age; @property (nonatomic,assign)NSMutableString height;
(id) mutableCopyWithZone:(NSZone *)zone { NSLog(@"%d",zone);
NSLog(@"可变"); Person *mutableCopyPerson=[[Person allocWithZone:zone] init]; mutableCopyPerson.name=[self.name mutableCopy]; mutableCopyPerson.sex=[self.sex copy]; mutableCopyPerson.height=[self.height mutableCopy ]; mutableCopyPerson.age=[self.age mutableCopy];
return mutableCopyPerson; } Person _person=[[Person alloc] init]; _person.name=[NSMutableString stringWithString:@"唐余猛"]; _person.sex=@"男"; _person.height=[NSMutableString stringWithString:@"171"]; _person.age=@"24"; Person copyPerson=[_person copy];//走的copyWithZone方法 Person *mutableCopy=[_person mutableCopy];//走的是mutableCopyWithZone方法
这时候疑问就来了,我设置一个可变的自定义类,内部的属性设置成不可变呢?答案很简单,mutableCopyWithZone和copyWithZone只会对这个对象拷贝,不会对这个对象的属性拷贝。那么这样的话mutableCopyWithZone,和copyWithZone用起来对一个自定义对象有什么区别呢。 这个是属于你对这个类的设计目标,比如你要设计一个Person类,如果不需要外界来修改它,那就是不可变的, 如果需要外界修改它,那就建个MutablePerson, 并加上相应的修改数据成员的方法, 这完全取决你的设计。 但是事实上,我们自己写代码时,很少遵循这种可变,不可变类的这种模式,通常都是建一个类,提供相应的设置方法。 事实上,只有CocoaTouch, string, dictionary, array这些基础的数据类型,才按这种模式来,一般的Model 类,基本不这么弄, 按这种模式来,写起来也麻烦,每种规则并不一是一定的。 对于自定义的类,如果我们想要实现copy的语义,我们需要实现NSCopying, NSMutableCopying这2个protocol。 如果有不对的地方希望大家指出来