如何在Objective-C中复制对象

时间:2009-09-22 11:47:41

标签: objective-c copy

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

6 个答案:

答案 0 :(得分:187)

与参考类型一样,有两种“复制”概念。我相信你知道他们,但是为了完整。

  1. 按位复制。在这里,我们只是将内存位复制一下 - 这就是NSCopyObject的作用。几乎总是,这不是你想要的。对象具有内部状态,其他对象等,并且经常假设它们是唯一持有对该数据的引用的对象。按位副本打破了这个假设。
  2. 深刻的逻辑副本。在这里,我们制作了一个对象的副本,但实际上没有一点一点地做 - 我们想要一个对所有意图和目的行为相同的对象,但不是(必然)原始的内存相同的克隆 - Objective C手册将这个对象称为“功能独立”的原始对象。因为制作这些“智能”副本的机制因类而异,我们要求对象本身执行它们。这是NSCopying协议。
  3. 你想要后者。如果这是您自己的对象之一,则只需采用协议NSCopying并实现 - (id)copyWithZone:(NSZone *)区域。你可以自由地做任何你想做的事情;虽然这个想法是你自己制作一个真实的副本并将其归还。您可以在所有字段上调用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;
    }
    

答案 1 :(得分:23)

Apple文档说

  

copyWithZone:方法的子类版本应该发送消息   超级首先,要包含它的实现,除非是子类   直接从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;
}

答案 2 :(得分:21)

我不知道该代码和我的代码之间的区别,但是我对该解决方案有疑问,所以我再读一点,发现我们必须在返回之前设置对象。我的意思是:

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

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

答案 3 :(得分:2)

another.obj = [obj copyWithZone: zone];

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

我认为应该是:

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

或:

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

答案 4 :(得分:0)

还有使用 - &gt;复制操作员。例如:

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

这里的推理是生成的复制对象应该反映原始对象的状态。 &#34;。&#34;运算符可以引入副作用,因为这会调用getter,而getter又可能包含逻辑。

答案 5 :(得分:0)

这可能是不受欢迎的方式。但是我该怎么做:

@Html.AntiForgeryToken()

非常简单直接。 :P