Object-c 浅拷贝

来源:互联网 发布:在淘宝卖保健品的要求 编辑:程序博客网 时间:2024/05/20 18:55
Objective-C 浅析Copy语法 - c语言程序开发技术文章 - 红黑联盟

http://www.2cto.com/kf/201402/276478.html


在OC语法中,提供了Copy语法(Copy + MutableCopy)用于对象的拷贝。其中很容易混淆的是浅拷贝和深拷贝。

浅拷贝,即是地址拷贝,并不产生新的对象,而是对原对象的引用计数值加1。

深拷贝,即是对象拷贝,产生新的对象副本,计数器为1。

下面通过一个例子来分析一下这个比较容易乱的Copy:

一、对于NSString/NSMutableString; NSArray/NSMutableArray... 这OC提供的类对象:

以NSString/NSMutableString为例:

对于copy,返回的一定是不可变类型;而mutableCopy,返回的一定是可变类型。

①对于 mutableCopy ,一定是深拷贝。

[objc] view plaincopy
  1. //对于 mutableCopy,都是深拷贝:对象的拷贝,产生新的对象  
  2. void strMutableCopy(){  
  3.        
  4.     NSString *str=[[NSString alloc]initWithFormat:@"abcd"];  
  5. //    NSMutableString *str = [[NSMutableString alloc] initWithFormat:@"abcd"];  
  6.        
  7.     //产生了一个新的对象 计数器为1 源对象的计数器不变  
  8.     NSMutableString *str2=[str mutableCopy];  
  9. //    NSString *str2 = [str mutableCopy];  
  10.        
  11.     //输出二者的地址,二者的地址是不同的  
  12.     NSLog(@"str --> %p",str);  
  13.     NSLog(@"str2 --> %p",str2);  
  14. }  
②对于 copy:

如果是 NSString ---> NSString;则是浅拷贝;如果是 NSMutableString ---> NSString;则是 深拷贝。

如果是 NSString 、NSMutableString ---> NSMutableString;则是深拷贝。

注:只有一种情况下是发生浅拷贝:不可变对象 复制到 不可变对象。

[objc] view plaincopy
  1. //浅拷贝:指针拷贝 不会产生新的对象,源对象计数器加1  
  2. void strCopy(){  
  3.        
  4.     NSString *str=[[NSString alloc]initWithFormat:@"abcd"];  
  5.     //因为NSString对象本身就不可变,所以并没产生新的对象,而是返回对象本身,会做一次retain操作,所以源对象也会retain  
  6.     NSString *str2=[str copy];  
  7.            
  8.     //输出二者的地址,二者的地址是相同的  
  9.     NSLog(@"str --> %p",str);  
  10.     NSLog(@"str2 --> %p",str2);  
  11. }  
除了以上这种情形外,其他都是深拷贝。
例如:

[objc] view plaincopy
  1. //深拷贝  
  2. void mutableStrCopy(){  
  3.        
  4.     NSMutableString *str=[[NSMutableString alloc]initWithFormat:@"abcd"];  
  5.        
  6.     //会产生一个新的对象计数器1  
  7.     NSString *str2=[str copy];  
  8.        
  9.     //输出二者的地址,二者的地址是不同的  
  10.     NSLog(@"str --> %p",str);  
  11.     NSLog(@"str2 --> %p",str2);  
  12. }  
二、对于自定义对象的Copy:该类必须实现NSCopying协议,重写 copyWithZone 方法。


同理,对于自定义对象的mutableCopy:必须实现 NSMutableCopying 协议,重写 mutableCopyWithZone 方法。

在NSCopying协议中,其实只有一个协议方法:
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end

在NSMutableCopying协议:
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end

下面给出一个例子:

[objc] view plaincopy
  1. #import <foundation foundation.h>  
  2. @interface Person : NSObject<nscopying>  
  3.    
  4. @property(nonatomic,assign)int age;  
  5. @property(nonatomic,copy)NSString *name;  
  6.    
  7. -(instancetype)initWithAge:(int)age withName:(NSString*)name;  
  8.    
  9. @end  
  10.   
  11. #import "Person.h"  
  12. @implementation Person  
  13.    
  14. -(instancetype)initWithAge:(int)age withName:(NSString*)name{  
  15.     self = [super init];  
  16.     if (self) {  
  17.         self.age = age;  
  18.         self.name = name;  
  19.     }  
  20.     return self;  
  21. }  
  22.    
  23. -(id)copyWithZone:(NSZone *)zone{  
  24.     Person* person = [[[self class] allocWithZone:zone] initWithAge:self.age withName:self.name];  
  25.     return person;  
  26. }  
  27.    
  28. @end  
  29.   
  30.   
  31. {  
  32.     @autoreleasepool {  
  33.            
  34.         Person *p1 = [[Person alloc] initWithAge:20 withName:@"Jack"];  
  35.         Person *p2 = [p1 copy];  
  36.            
  37.         //输出两个 Person 对象的地址,二者是不同的  
  38.         NSLog(@"p1 --> %p",p1);  
  39.         NSLog(@"p2 --> %p",p2);  
  40.     }  
  41.     return 0;  
  42. }  
加入对于某些自定义对象是不可变的,那么如何办呢?
[objc] view plaincopy
  1. -(id)copyWithZone:(NSZone *)zone{  
  2.     return self;  
  3. }  
这样,输出的两个对象的地址就是相同的了

下面了解一下关于如果某一个自定义类继承了 这个Person类的情况。

如果某一个子类继承了实现了NSCopying协议的基类,那么该子类也是会自动继承这个协议的方法。但是需要自己重新实现。

例如:有一个Student子类继承了这个Person类:

[objc] view plaincopy
  1. #import <foundation foundation.h="">  
  2. #import "Person.h"  
  3. @interface Student : Person  
  4.    
  5. @property(nonatomic,copy)NSString *school;  
  6.    
  7. -(instancetype)initWithAge:(int)age withName:(NSString *)name WithSchool:(NSString*)school;  
  8.    
  9. @end  
  10.   
  11. #import "Student.h"  
  12.    
  13. @implementation Student  
  14.    
  15. -(instancetype)initWithAge:(int)age withName:(NSString *)name WithSchool:(NSString*)school{  
  16.     self = [super initWithAge:age withName:name];  
  17.     if (self) {  
  18.         self.school = school;  
  19.     }  
  20.     return self;  
  21. }  
  22.    
  23. -(id)copyWithZone:(NSZone *)zone{  
  24.     Student *student = [super copyWithZone:zone];  
  25.     student.school = self.school;  
  26.     return student;  
  27. }  
  28.    
  29. @end  
注意其中copyWithZone方法的实现。
0 0