NSString @property, используя копию вместо сохранения

Я просматриваю образец приложения Apple EditableDetailView и заметил, что в одном из своих контроллеров они устанавливают экземпляр свойства NSString с помощью (nonatomic, copy). Когда можно использовать копию вместо сохранения? Это так, чтобы они могли сделать уникальную копию, не затрагивая существующие данные?

Ответов (3)

Решение

Да, это так, чтобы он мог сделать уникальную копию, не затрагивая существующие данные. Синтезированные сеттеры по сути выглядят так:

// For @synthesize(nonatomic, retain) foo:
- (void) setFoo(NSFoo *theFoo)
{
    [theFoo retain];  // retain new value
    [foo release];    // release old value, if any
    foo = theFoo;     // assign new value
}

// For @synthesize(nonatomic, copy) foo:
- (void) setFoo(NSFoo *theFoo)
{
    NSFoo* newFoo = [theFoo copy];  // make copy
    [foo release];  // release old value, if any
    foo = newFoo;   // assign new value
}

Обратите внимание, что порядок операций здесь важен - новое значение должно быть сохранено / скопировано до того, как старое значение будет выпущено, в случае самоназначения. Если вы сначала освободили, а затем присвоили свойство самому себе, вы можете случайно освободить значение. Также обратите внимание, что если старое значение равно nil, отправка ему release сообщения - это нормально, поскольку отправка сообщения nil объекту явно разрешена и ничего не делает.

Выбор между сохранением или копированием просто определяет, имеет ли свойство объекта то же значение, что и вы его устанавливаете. Рассмотрим следующий код:

// suppose the 'foo' property is declared 'retain' and the 'bar' property is
// declared 'copy'
NSFoo *foo = ...;
NSBar *bar = ...;
someObject.foo = foo;
someObject.bar = bar;
[foo changeInternalState];  // someObject.foo also changes, since it's the same object
[bar changeInternalState];  // someObject.bar does NOT change, since it's a copy

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

Вы можете сказать: «Почему бы мне просто не скопировать строку, прежде чем назначать ее туда?». Возможно, объекту нужна изменяемая строка, а ваша неизменяемая. Если вам нужно сначала скопировать строку, вам нужно найти, какой тип строки он хочет, в документации или заголовке, а затем делать правильную копию (каждый раз). Таким образом, вы просто говорите, other.string = myString и он делает любую копию, которую хочет - вам не нужно об этом беспокоиться.

(По какой-то причине этот пост появляется над следующим вопросом, на который я пытаюсь ответить) Re:

Вы имели в виду, что я должен скопировать объект 'the foo' перед выпуском 'foo' ?? но в чем проблема, если я перезапущу 'foo' перед копированием 'foo' ?? потому что это два разных объекта, я не могу понять, почему освобождение одного влияет на другое !!!!

В большинстве случаев вы правы. Если это на самом деле два отдельных объекта, это не имеет значения. Проблема заключается в том, что вы присваиваете один и тот же объект самому себе. Если бы вы сказали

[myObject setFoo: moof];
[myObject setFoo: moof];

Затем, когда вы это сделаете второй раз, вы выпустите moof перед тем, как скопировать его. В промежуточный момент возможно, что если счетчик сохранения moof станет нулевым, то moof будет удален, и вам нечего будет копировать на следующем шаге. Теперь Foo будет равно нулю.

Возможно ли это? Наверное, больше, чем вы думаете. Конечно, бывают случаи, когда пользователь, например, может дважды щелкнуть кнопку «обновить».

Надеюсь, это понятно и полезно.