看官们,我们在前面章回中介绍了OC中对象的复制,本章回中将继续介绍这方面的知识。
在上一章回中我们介绍了什么是复制以及如何进行复制。本章回中将介绍复制背后的原理和复制操作的原则。
复制的原理
我们通过复制操作的两个方法(copy和mutableCopy)进行复制操作时本质上是在调用`copyWithZone`和`mutableCopyWithZone`这两个方法.这两个方法是`NSCopying`和`NSMutableCopying`协议中的方法,而NSObject类实现了这两个协议并且重写了协议中的这两个方法。因此,我们在自己定义的类中重写这两个方法就可以实现复制操作。如果不重写这两个方法就进行复制操作,那么会导致运行时发生异常。下面是重写方法的示例代码。
-(id) copyWithZone:(NSZone *)zone
{
NSLog(@"copying");
//给各个属性赋值
}
-(id) mutableCopyWithZone:(NSZone *)zone
{
NSLog(@"mutable copying");
//给各个属性赋值
}
对于OC中的类以及Foundation框架中提供的类,我们可以直接使用copy方法来实现复制操作,因为这些类已经重写了`copyWithZone`和`mutableCopyWithZone`这两个方法。
复制的原则
这里说的原则主要有两个方面,一方面指深浅复制,另一方面指新复制出来的对象是否可以被修改。
- 对于自定义的类,我们的原则是:使用深复制并且复制出来的新对象可以被修改。也就是说不管使用copy方法还是mutableCopy方法,复制操作都是深复制,复制出来的对象都可以被修改。
- 对于OC中的类,如果类的对象是不可变的(比如NSString),copy方法是浅复制,复制出来的对象不可以被修改。 mutableCopy方法是深复制,复制出来的对象可以被修改。
- 对于OC中的类,如果类的对象是可变的(比如NSMutableString),copy方法和mutableCopy方法都是深复制,复制出来的对象都可经被修改。
对于使用等号进行赋值操作,它相当于浅复制,不管被复制的对象是否可变,它只是复制一个引用并没有创建新的对象。
对于自定义的类,在自定义类中实现复制操作的方法时需要遵守刚才说过的原则。对于OC中的类,复制操作的方法已经实现,我们可以通过代码来验证这些方法执行的原则。下面是一个示例代码,请大家参考:
#include <Foundation/Foundation.h>
@interface Book : NSObject
@property (nonatomic,readwrite,strong) NSString *name;
@property (nonatomic,readwrite,strong) NSMutableString *group;
@property (nonatomic,readwrite,copy) Book* test;
@property (nonatomic,readwrite) int price;
-(void) show;
@end
@implementation Book
@synthesize name;
@synthesize price;
@synthesize group;
@synthesize test;
-(void) show
{
NSLog(@"----Book Inof----");
NSLog(@"name: %@ -- %p",name,name);
NSLog(@"group: %@ -- %p",group,group);
NSLog(@"test: %@ -- %p",test,test);
NSLog(@"price: %d" ,price);
NSLog(@"-----------------");
}
//自己定义copy方法,其原则是深复制。使用mutableCopy方法实现深复制
-(id) copyWithZone:(NSZone *)zone
{
NSLog(@"copying");
Book *obj = [[[self class] allocWithZone:zone] init];
obj.name = [self.name mutableCopy];
obj.group = [self.group mutableCopy];
obj.test = [self.test mutableCopy];
obj.price = self.price;
return obj;
}
-(id) mutableCopyWithZone:(NSZone *)zone
{
NSLog(@"mutable copying");
//直接使用交类的copy原则
// id obj = [super mutableCopy];
//直接使用自己的copy原则
id obj = [self copy];
return obj;
}
@end
int main()
{
NSString *str1 = @"abc";
NSString *str2 = [str1 copy];
NSString *str3 = [str1 mutableCopy];
//NSString对象,copy方法执行浅复制,mutableCopy方法执行深复制
NSLog(@"string1 : %@ -- %p",str1,str1);
NSLog(@"string2 : %@ -- %p",str2,str2);
NSLog(@"string3 : %@ -- %p",str3,str3);
NSArray *arr1 = [NSArray arrayWithObjects:@"aa",@"bb",@"cc",nil];
NSArray *arr2 = [arr1 copy];
NSArray *arr3 = [arr1 mutableCopy];
//NSArray这类不可变对象,copy方法执行浅复制,mutableCopy方法执行深复制
NSLog(@"array1: %@ -- %p",arr1,arr1);
NSLog(@"array2: %@ -- %p",arr2,arr2);
NSLog(@"array3: %@ -- %p",arr3,arr3);
NSMutableArray *mutArr1 = [NSMutableArray arrayWithObjects:@"aa",@"bb",@"cc",nil];
NSMutableArray *mutArr2 = [mutArr1 copy];
NSMutableArray *mutArr3 = [mutArr1 mutableCopy];
//NSMutableArray这类可变对象,copy方法和mutableCopy方法都执行深复制
NSLog(@"mutabArray1: %@ -- %p",mutArr1,mutArr1);
NSLog(@"mutabArray2: %@ -- %p",mutArr2,mutArr2);
NSLog(@"mutabArray3: %@ -- %p",mutArr3,mutArr3);
Book *b1 = [[Book alloc] init];
[b1 setName:@"book1"];
[b1 setPrice:1];
[b1 setGroup:@"group1"];
NSLog(@"Book1 --->");
[b1 show];
NSLog(@"Address: %p",b1);
Book *b2 = [[Book alloc] init];
//设置成copy属性后会调用类的copy方法
[b2 setTest:b1];
NSLog(@"Book2 --->");
[b2 show];
}
在示例代码中演示了自定义类如何通过重写copy和mutalbeCopy方法来实现复制操作.同时也通过打印对象地址的方式演示了OC中类的复制原则,我们在相关地方都添加了注释,不过还是希望大家自己动手来实践,这样可以加深对这些复制原则的理解。
最后我们对本章回的内容做一个总结:
- 1.复制操作表面是使用i`copy`和`mutableCopy`方法实现,但是本质上是通过`copyWithZone`和`mutableCopyWithZone`这两个方法实现的;
- 2.自定义的类中需要实现`copyWithZone`和`mutableCopyWithZone`这两个方法,不然进行复制操作时会引发运行时异常;
- 3.OC中提供的类已经实现了`copyWithZone`和`mutableCopyWithZone`这两个方法,我们直接进行复制操作就可以;
- 4.我们需要明白OC提供类所遵守的复制原则,同时在自定义类时需要遵守自定义类的复制原则;
看官们,本章回的内容就介绍到这里,欲知后事如何且听下回分解!