ObjC里面应该是没有深浅拷贝这个概念,但是实际在用的过程中我发现了这样的问题,也就是当对象A和对象B同时指向内存中同一个内容时,对象B若改变了该值,则对象A也会相应的改变该值。这就出现了一个问题,而这个问题跟C++中的深浅拷贝的思想不约而同的一致。大致思想是这样,我们来通过一下几个代码来具体看看。
有5个文件,分别是Point.h Point.m Rectangle.h Rectangle.m 和 main.m
Rectangle里包含了Point对象。main是主函数。
// Point.h
#import <foundation/Foundation.h>
@interface XYPoint: NSObject
@property int x, y;
-(void) setX: (int) xVal andY: (int) yVal;
@end
// Point.m
#import "Point.h"
@implementation XYPoint
@synthesize x, y;
-(void) setX: (int) xVal andY: (int) yVal
{
x = xVal;
y = yVal;
}
@end
// Rectangle.h
#import <Foundation/Foundation.h>
@class XYPoint;
@interface Rectangle: NSObject
@property int width, height;
-(XYPoint*) origin;
-(void) setOrigin: (XYPoint*) pt;
-(void) setWidth: (int) w andHeight: (int) h;
-(void) setDeepOrigin: (XYPoint*) pt;
@end
// Rectangle.m
#import "Rectangle.h"
#import "Point.h"
@implementation Rectangle
{
XYPoint* origin;
}
@synthesize width, height;
-(void) setWidth: (int) w andHeight: (int) h
{
width = w;
height = h;
}
-(void) setOrigin: (XYPoint*) pt
{
origin = pt;
}
-(void) setDeepOrigin: (XYPoint*) pt
{
if (!origin)
origin = [[XYPoint alloc] init];
[origin setX: [pt x] andY: [pt y]];
}
-(XYPoint*) origin
{
return origin;
}
@end
// main.m
#import "Point.h"
#import "Rectangle.h"
int main (int argc, char* argv[])
{
@autoreleasepool{
Rectangle* rec = [[Rectangle alloc] init];
XYPoint* ptr = [[XYPoint alloc] init];
[ptr setX: 100 andY: 200];
[rec setWidth: 5 andHeight: 8];
[rec setDeepOrigin: ptr];
NSLog(@"Rectangle w = %i, h = %i", [rec width], [rec height]); // rec.width is also OK.
NSLog(@"Origin at (%i, %i)", [[rec origin] x], [[rec origin] y]);
[ptr setX: 999 andY: 999];
NSLog(@"深拷贝Origin at (%i, %i)", [[rec origin] x], [[rec origin] y]);
[rec setOrigin: ptr];
[ptr setX: 999 andY: 999];
NSLog(@"浅拷贝Origin at (%i, %i)", [[rec origin] x], [[rec origin] y]);
}
return 0;
}
可以看到深浅拷贝的区别了。
虽说ObjC中没有明确的深浅拷贝概念,但是C++的深浅拷贝思想可以移植到ObjC来。
同时值得注意的是,这里还用到了一个C++组合(composition)的概念,也就是说,Point是作为Rectangle的成员的,而且在Rectangle的接口中声明了@class XYPoint后就不用导入Point的头文件了,系统会默认把Point作为一个类来处理。但是Point的成员函数和成员变量无法使用,因为系统此时只知道它是一个类,而不清楚它的成员函数和变量是什么,如果要引用它的成员函数和变量的话,那么就需要导入Point的头文件。