Лучшая практика для копирования частных экземпляров с NSCopying

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

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

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

Спасибо.

Ответ 1

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

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

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

Ответ 2

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

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

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

- (id)copyWithZone:(NSZone *)zone {
    MyCopyableClass *theCopy = [[[self class] allocWithZone:zone] init];
    theCopy->anInstanceVariable = anInstanceVariable;
    return theCopy;
}

Ответ 3

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

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

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