2009-09-22 2 views
104

Мне нужно выполнить глубокую копию пользовательского объекта, который имеет собственные объекты. Я читал и немного смущен относительно того, как наследовать NSCopying и как использовать NSCopyObject. Может ли кто-нибудь помочь мне? Спасибо за прочтение!Как скопировать объект в объекте c

+1

Великий [учебник] (http://www.techotopia.com/index.php/Copying_Objects_in_Objective-C) для понимания копии, mutableCopy и copyWithZone – horkavlna

ответ

182

Как всегда с ссылочными типами существует два понятия «копировать». Я уверен, что вы их знаете, но для полноты.

  1. Побитовая копия. В этом случае мы просто копируем бит памяти для бит - это то, что делает NSCopyObject. Почти всегда, это не то, что вы хотите. Объекты имеют внутреннее состояние, другие объекты и т. Д., И часто делают предположения, что они являются единственными, у которых есть ссылки на эти данные. Побитовые копии нарушают это предположение.
  2. Глубокая, логическая копия. В этом случае мы создаем копию объекта, но фактически не выполняем его по-разному - мы хотим, чтобы объект, который ведет себя одинаково для всех целей и целей, но не является (обязательно) идентичным памяти клоном оригинала - в руководстве Objective C такой объект «функционально независим» от оригинала. Поскольку механизмы создания этих «интеллектуальных» копий варьируются от класса к классу, мы просим сами объекты выполнить их. Это протокол NSCopying.

Вы хотите последнего. Если это один из ваших собственных объектов, вам нужно просто принять протокол 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; 
} 
+0

Но вы делаете получателя скопированного объекта ответственным за его освобождение! Разве вы не 'autorelease' его, или я что-то упустил здесь? – bobobobo

+29

@bobobobo: Нет, основное правило памяти Objective-C управление: вы получаете право собственности на объект, если вы его создаете, используя метод, имя которого начинается с «alloc» или «new» или содержит «copy». 'copyWithZone:' соответствует этим критериям, поэтому он должен возвращать объект с сохранением count +1. –

+1

@Adam Есть ли причина использовать 'alloc' вместо' allocWithZone: ', поскольку зона была передана i n? – Richard

22

Apple, документация говорит

A subclass version of the copyWithZone: method should send the message to super first, to incorporate its implementation, unless the subclass descends directly from 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; 
} 
+1

Поскольку YourClass спускается непосредственно из NSObject, я не думаю, что это необходимо здесь – Mike

+2

Хорошая точка, но это общее правило, если это длинная иерархия классов. –

+8

У меня есть ошибка: 'Нет видимого @interface для 'NSObject' объявляет селектор 'copyWithZone:''. Я предполагаю, что это требуется только тогда, когда мы наследуем какой-то другой пользовательский класс, который реализует 'copyWithZone' – Sam

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

Я думаю, что эта линия вызывает утечку памяти, потому что вам доступ до obj через имущество, которое (я предполагаю) объявлено как retain. Таким образом, сохранить кол-во будет увеличено по собственности и copyWithZone.

Я считаю, что это должно быть:

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

или:

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

Нет, методы alloc, copy, mutableCopy, new должны возвращать неавтореализованные объекты. – kovpas

+0

@kovpas, вы уверены, что вы меня правильно поняли? Я не говорю о возвращенном объекте, я говорю о его полях данных. –

+0

да, мой плохой, извините. не могли бы вы отредактировать свой ответ так или иначе, чтобы я мог удалить минус? :)) – kovpas

19

я не знаю различие между этим кодом и моим, но у меня есть проблемы с этим решением, так что я прочитал немного больше и обнаружил, что мы должны установить объект перед его возвратом. я имею в виду что-то вроде

#import <Foundation/Foundation.h> 

@interface YourObject : NSObject <NSCopying> 

@property (strong, nonatomic) NSString *nombre;//nombre del medicamento 
@property (strong, nonatomic) NSString *linea;//linea a la que pertenece 
@property (strong, nonatomic) NSMutableString *tags;//palabras por las que se puede encontrar en el buscador 
@property (strong, nonatomic) NSString *htmlSource;//código html para mostrar su contenido 
@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.nombre]; 
    [copy setLinea: self.linea]; 
    [copy setTags: self.tags]; 
    [copy setHtmlSource: self.htmlSource]; 

    return copy; 
} 

я помещал этот ответ причину, у меня есть много проблем, связанных с этим вопросом, и я понятия не имеют о том, почему!, я не знаю разницу, но это работает и, возможно, может быть полезным:)

0

Существует также использование оператора -> для копирования. Например:

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

Приведенная здесь копия объекта должна отражать состояние исходного объекта. «.«оператор может вводить побочные эффекты, так как это вызывает геттеры, которые, в свою очередь, могут содержать логику.

Смежные вопросы