Мне нужно глубоко копировать пользовательский объект, который имеет свои собственные объекты. Я читал вокруг и немного запутался, как наследовать NSCopying и как использовать NSCopyObject.
Как скопировать объект в Objective-C
Ответ 1
Как всегда со ссылочными типами, существует два понятия "копировать". Я уверен, что вы их знаете, но для полноты.
- Побитовая копия. В этом случае мы просто копируем бит памяти для бит - это то, что делает NSCopyObject. Почти всегда, это не то, что вы хотите. Объекты имеют внутреннее состояние, другие объекты и т.д., И часто делают предположения, что они являются единственными, у которых есть ссылки на эти данные. Побитовые копии нарушают это предположение.
- Глубокая логическая копия. В этом случае мы создаем копию объекта, но фактически не выполняем его по-разному - мы хотим, чтобы объект, который ведет себя одинаково для всех целей и целей, но не является (обязательно) идентичным памяти клоном оригинала - руководство 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;
}
Ответ 2
В документации 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;
}
Ответ 3
Я не знаю разницы между этим кодом и моим, но у меня есть проблемы с этим решением, поэтому я прочитал немного больше и обнаружил, что мы должны установить объект, прежде чем возвращать его. Я имею в виду что-то вроде:
#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;
}
Я добавил этот ответ, потому что у меня много проблем с этим вопросом, и я понятия не имею, почему это происходит. Я не знаю разницы, но это работает для меня, и, возможно, это может быть полезно и для других:)
Ответ 4
another.obj = [obj copyWithZone: zone];
Я думаю, что эта строка вызывает утечку памяти, потому что вы получаете доступ к obj
через свойство, которое (я предполагаю) объявлено как retain
. Таким образом, сохранение количества будет увеличено по свойству и copyWithZone
.
Я считаю, что это должно быть:
another.obj = [[obj copyWithZone: zone] autorelease];
или
SomeOtherObject *temp = [obj copyWithZone: zone];
another.obj = temp;
[temp release];
Ответ 5
Существует также использование оператора → для копирования. Например:
-(id)copyWithZone:(NSZone*)zone
{
MYClass* copy = [MYClass new];
copy->_property1 = self->_property1;
...
copy->_propertyN = self->_propertyN;
return copy;
}
Приведенная здесь результирующая скопированная объект должна отражать состояние исходного объекта. "." оператор может ввести побочные эффекты, так как это вызывает геттеры, которые, в свою очередь, могут содержать логику.