如何在 Objective-C 中复制对象

我需要深度复制一个自定义对象,它有自己的对象。我一直在阅读,对于如何继承 NSCopying 和如何使用 NSCopyObject 感到有点困惑。

117511 次浏览

与引用类型一样,“复制”有两个概念。我相信你们都知道,但是为了完整起见。

  1. 按位复制。在这里,我们只复制位的内存位-这就是 NSCopyObject 所做的。几乎总是,这不是你想要的。对象具有内部状态、其他对象等,并且经常假设它们是唯一保存对该数据的引用的对象。按位拷贝打破了这种假设。
  2. 一个深刻的,符合逻辑的副本。在这种情况下,我们复制一个对象,但是不需要一点一点地去做——我们希望一个对象在所有的意图和目的上都是一样的,但是并不(必然)是原始对象的一个内存相同的克隆—— Objective C 手册称这样的对象与原始对象“功能独立”。因为创建这些“智能”副本的机制因类而异,所以我们要求对象本身执行它们。这是 NSCopying 协议。

你想要后者。如果这是您自己的对象之一,您只需采用协议 NSCopying 并实现-(id) copWithZone: (NSZone *) zone。你可以自由地做任何你想做的事情,尽管你的想法是复制一个真实的自己,然后归还它。您可以在所有字段上调用 CopyWithZone 来进行深度复制。一个简单的例子是

@interface YourClass : NSObject <NSCopying>
{
SomeOtherObject *obj;
}


// In the implementation
-(id)copyWithZone:(NSZone *)zone
{
// We'll ignore the zone for now
YourClass *another = [[YourClass alloc] init];
another.obj = [obj copyWithZone: zone];


return another;
}

苹果的文件显示

CopWithZone: 方法的子类版本应该发送消息 超级优先,合并它的实现,除非子类 直接从 NSObject 下降。

增加现有的答案

@interface YourClass : NSObject <NSCopying>
{
SomeOtherObject *obj;
}


// In the implementation
-(id)copyWithZone:(NSZone *)zone
{
YourClass *another = [super copyWithZone:zone];
another.obj = [obj copyWithZone: zone];


return another;
}
another.obj = [obj copyWithZone: zone];

我认为,这一行会导致内存泄漏,因为您通过(我假设)声明为 retain的属性访问 obj。因此,保留计数将增加的性质和 copyWithZone

我认为应该是:

another.obj = [[obj copyWithZone: zone] autorelease];

or:

SomeOtherObject *temp = [obj copyWithZone: zone];
another.obj = temp;
[temp release];

我不知道那段代码和我的有什么不同,但是我在这个解决方案上遇到了一些问题,所以我又读了一些,发现我们必须在返回对象之前设置它。我的意思是:

#import <Foundation/Foundation.h>


@interface YourObject : NSObject <NSCopying>


@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *line;
@property (strong, nonatomic) NSMutableString *tags;
@property (strong, nonatomic) NSString *htmlSource;
@property (strong, nonatomic) NSMutableString *obj;


-(id) copyWithZone: (NSZone *) zone;


@end




@implementation YourObject




-(id) copyWithZone: (NSZone *) zone
{
YourObject *copy = [[YourObject allocWithZone: zone] init];


[copy setNombre: self.name];
[copy setLinea: self.line];
[copy setTags: self.tags];
[copy setHtmlSource: self.htmlSource];


return copy;
}

我加上这个答案是因为我在这个问题上有很多问题,而且我不知道为什么会发生这种情况。我不知道其中的区别,但它对我很有用,也许对其他人也有用:)

还可以使用-> 操作符进行复制。例如:

-(id)copyWithZone:(NSZone*)zone
{
MYClass* copy = [MYClass new];
copy->_property1 = self->_property1;
...
copy->_propertyN = self->_propertyN;
return copy;
}

这里的推理是,由此产生的复制对象应该反映原始对象的状态。那个运算符可能会引入副作用,因为这个运算符调用 getter 函数,而 getter 函数又可能包含逻辑。

这种方式可能不受欢迎,但我是这么做的:

object1 = // object to copy


YourClass *object2 = [[YourClass alloc] init];
object2.property1 = object1.property1;
object2.property2 = object1.property2;
..
etc.

Quite simple and straight forward. :P