繁体   English   中英

如何在Objective-C中复制对象

[英]How to copy an object in Objective-C

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

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

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

你想要后者。 如果这是您自己的对象之一,您只需采用 NSCopying 协议并实现 -(id)copyWithZone:(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;
}

苹果文档说

copyWithZone: 方法的子类版本应该首先将消息发送到 super,以合并其实现,除非子类直接从 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;
}

我不知道那个代码和我的有什么区别,但是我对那个解决方案有问题,所以我读了一点,发现我们必须在返回之前设置对象。 我的意思是这样的:

#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;
}

我添加了这个答案是因为我在这个问题上有很多问题,我不知道为什么会这样。 我不知道有什么区别,但它对我有用,也许对其他人也有用:)

another.obj = [obj copyWithZone: zone];

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

我认为应该是:

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

要么:

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

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

-(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.

非常简单直接。 :P

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM