Лучшая практика для копирования личных экземпляров с помощью NSCopying - PullRequest
10 голосов
/ 02 апреля 2010

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

В моей реализации copyWithZone: мне нужно выделить / инициализировать новый экземпляр, но также настроить его состояние в соответствии с текущим экземпляром. Очевидно, я могу получить доступ к текущему приватному состоянию изнутри copyWithZone:, но не могу установить его в новый объект, потому что для этого состояния нет средств доступа.

Есть ли стандартный способ обойти это, сохраняя конфиденциальность данных?

Спасибо.

Ответы [ 3 ]

8 голосов
/ 02 апреля 2010

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

Во-вторых, предложение Алекса об использовании -> является стандартным подходом, даже если это нарушает приведенное выше правило получения. Есть небольшое количество исключений из этого правила, и копия является одним из. Использование частных сеттеров здесь все еще целесообразно (и я делал это исключительно так), но я обнаружил, что по разным причинам использование -> часто работает чище.

Будьте очень осторожны, чтобы правильно настроить управление памятью. Если вам нужно позвонить по номеру [super copyWithZone:], вам следует также прочитать о сложностях NSCopyObject() и о том, как это повлияет на вас, даже если вы сами его не используете. Я подробно обсуждал это в «NSCopyObject () считается вредным».

5 голосов
/ 02 апреля 2010

Вы можете получить доступ к переменным экземпляра копии напрямую. Вы используете тот же синтаксис разыменования указателя, что и со структурой. Так, например, если ваш класс это:

@interface MyCopyableClass : NSObject {
    int anInstanceVariable;
}
@end

Вы можете сделать это:

- (id)copyWithZone:(NSZone *)zone {
    MyCopyableClass *theCopy = [[[self class] allocWithZone:zone] init];
    theCopy->anInstanceVariable = anInstanceVariable;
    return theCopy;
}
1 голос
/ 02 апреля 2010

Один из вариантов - создать собственный инициализатор, который принимает частные значения iVar. Таким образом, вы создаете это как:

-(id) initWithPropertyOne:(SomeClass *) anObject andPropertyTwo:(SomeClass *) anotherObject;

Когда вы создаете копию, просто используйте пользовательский инициализатор.

...