Как использовать свойство "copy" в Objective-C?

Я прочитал много материалов в Интернете, которые объясняют, когда люди должны использовать "copy" вместо "strong".

"Атрибут копирования является альтернативой сильному. Вместо того, чтобы владеть существующим объектом, он создает копию того, что вы назначаете этому свойству, а затем берет на себя ответственность. Только объекты, соответствующие протоколу NSCopying может использовать этот атрибут..."

И есть много примеров кодов, показывающих при использовании "copy", исходное значение остается неизменным.

Однако я новичок в Objective-C. Я действительно хочу знать, как использовать вновь назначенное значение. Где находится "новый экземпляр (копия)" с "новым значением"? Нужны ли какие-либо дополнительные методы для изменения исходного значения, если я хочу?

Будет здорово, если кто-то может поделиться примером для этой части, а не тот, который доказывает, что исходное значение не изменяется, что есть везде.

Ответ 1

То, что атрибут copy делает за кулисами, так это создание сеттера следующим образом:

- (void)setMyCopiedProperty:(MyClass *)newValue {
    _myCopiedProperty = [newValue copy];
}

это означает, что всякий раз, когда кто-то делает что-то вроде этого object.myCopiedProperty = someOtherValue; , someOtherValue отправляется сообщение о copy котором говорится, что оно должно дублироваться. Затем получатель получает новый указатель (при условии, что copy правильно реализована), к которому никто, кроме объекта-получателя, не имеет доступа.

Вы можете посмотреть на copy как на эксклюзивную:

  • клиенты, которые устанавливают свойство, не имеют доступа к фактическому установленному значению
  • получатель не имеет доступа к исходному переданному значению.

Остерегайтесь предостережений, хотя:

  • скопированный NSArray не копирует свои объекты, поэтому вы можете подумать, что @property(copy) NSArray<MyClass *> *myProperty безопасен, однако, хотя сам массив защищен от изменения, объекты, @property(copy) NSArray<MyClass *> *myProperty в массиве поделиться той же ссылкой. То же самое верно для любого класса коллекции (NSDictionary, NSSet и т.д.)
  • если свойство соответствует пользовательскому классу, вам нужно убедиться, что метод copy выполняет свою работу - т.е. создает новый объект. Это происходит для всех классов Cocoa/CocoaTouch, которые соответствуют NSCopying, однако для других классов это может быть или не быть правдой, в зависимости от реализации (сам я еще не видел класс, который лежит о его методе copy, однако вы никогда не знаете)

Ответ 2

Попробуйте следующее:

model.h

@interface Model: NSObject

@property (nonatomic,strong)NSString *firstName;

@property (nonatomic,copy) NSString *lastName;

@end

ViewController.m

-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
Model *model = [[Model alloc]init];
NSMutableString *str = [[NSMutableString alloc]initWithString:@"test"];
model.firstName = str;
model.lastName = str;
NSLog(@"%@, %@", model.firstName, model.lastName);
[str appendString:@"string"];
NSLog(@"%@, %@ ", model.firstName, model.lastName);}

Ответ 3

Экземпляр класса представляет собой дискретную копию. Когда вы назначаете экземпляр класса как значение свойства с атрибутом copy, создается клон этого экземпляра и этот клон становится значением свойства. Между оригиналом и его клоном нет никакой связи, поэтому свойство вообще не имеет доступа к исходному экземпляру. Изменение атрибута значения свойства изменяет клон.

Примечание:

Если вы реализуете setter для свойства copy, вы несете ответственность за то, чтобы он действительно создавал копию. Как и во всех атрибутах для свойства, они имеют смысл только тогда, когда компилятор генерирует (синтезирует) установщик и/или получатель для вас.