Я мог бы пропускать что-то очевидное здесь, но я реализую NSCopying на одном из моих объектов. Тот объект имеет частные переменные экземпляра, которые не выставляются через методы считывания, поскольку они не должны использоваться вне объекта.
В моей реализации copyWithZone:
, Я нуждаюсь в alloc/init новый экземпляр, но также и настраиваю его состояние для соответствия текущему экземпляру. Я могу, очевидно, получить доступ к текущему частному состоянию изнутри copyWithZone:
, но я не могу установить его в новый объект, потому что нет никаких средств доступа для того состояния.
Существует ли стандартный путь вокруг этого при тихом сохранении конфиденциальности данных в целости?
Спасибо.
Во-первых, у вас всегда должны быть геттеры, даже если они частные. Ваш объект должен получать доступ даже даже к своим собственным ivars с помощью аксессоров (за исключением очень небольшого числа случаев). Это избавит вас от многих страданий, связанных с управлением памятью.
Во-вторых, предложение Алекса использовать -> является стандартным подходом, даже несмотря на то, что это нарушает приведенное выше правило геттеров. Есть небольшое количество исключений из этого правила, и копия - одно из них. Использование частных сеттеров здесь по-прежнему разумно (и раньше я делал это исключительно), но по разным причинам я обнаружил, что использование -> часто работает более чисто.
Будьте очень осторожны, чтобы правильно управлять памятью. Если вам нужно вызвать [super copyWithZone:]
, то вам также следует ознакомиться со сложностями NSCopyObject ()
и тем, как он влияет на вас, даже если вы не используете его сами. . Я подробно обсуждал это в «NSCopyObject () считается вредоносным».
Вы можете получить прямой доступ к переменным экземпляра копии. Для этого используется тот же синтаксис разыменования указателей, что и в случае со структурой. Так, например, если ваш класс такой:
@interface MyCopyableClass : NSObject {
int anInstanceVariable;
}
@end
Вы можете сделать так:
- (id)copyWithZone:(NSZone *)zone {
MyCopyableClass *theCopy = [[[self class] allocWithZone:zone] init];
theCopy->anInstanceVariable = anInstanceVariable;
return theCopy;
}
Один из вариантов - создать собственный инициализатор, который принимает частные значения iVar. Таким образом, вы создаете его так:
-(id) initWithPropertyOne:(SomeClass *) anObject andPropertyTwo:(SomeClass *) anotherObject;
Когда вы создаете копию, просто используйте специальный инициализатор.