Попытка использовать скопированное свойство NSMutableString вызывает исключение.

Я начал небольшой проект Xcode, чтобы выяснить, должно ли свойство NSMutableString быть copy или retain. Я объявил свою собственность с атрибутом copy:

@property (nonatomic,copy) NSMutableString *stringA;

Затем инициализировал его как self.stringA = [NSMutableString new];

наконец-то попробовал установить строку [stringA setString:@"A"];.

Однако программа дает,

«Завершение работы приложения из-за неперехваченного исключения 'NSInvalidArgumentException', причина: 'Попытка изменить неизменяемый объект с помощью setString:'»

Это потому, что результирующая строка - это NSString? Означает ли это, что я должен объявлять свои NSMutableString свойства, используя атрибут retain, и свойства NSString, используя copy?


person rustylepord    schedule 16.08.2012    source источник
comment
Вы почти наверняка не хотите, чтобы изменяемая строка была свойством; по крайней мере, не тот, который представлен как API.   -  person bbum    schedule 16.08.2012
comment
мой ответ слишком многословен: stackoverflow.com/ вопросы / 4995254 /   -  person justin    schedule 16.08.2012
comment
Бессмысленно использовать copy для NSStrings.   -  person Hot Licks    schedule 16.08.2012
comment
@HotLicks нет, это не так. запомните семантику! что произойдет, если клиент передаст изменяемую строку в качестве параметра вашему классу, вы сохраните ее, а затем они изменят ее за вашей спиной? плохие вещи. простое решение - сделать копию - если параметр изменяемый, значит, у вас есть правильность и строка, которую вы можете легко передать, не создавая дополнительных копий. если он неизменяемый, то он может return [self retain] без создания глубокой копии.   -  person justin    schedule 16.08.2012
comment
До сих пор я понял, что копирование важно в NSString, но не в NSMutableString. Поскольку NSMutableString является подклассом NSString, вы можете назначить NSMutableString для NSString. Поправьте меня, если я здесь не прав.   -  person rustylepord    schedule 16.08.2012
comment
@rustylepord ну, дело не в том, что это неважно - «проблема» в том, что -[NSMutableString copy] создает неизменяемую копию. для изменяемой копии вы должны использовать mutableCopy. mutablecopy не является спецификатором свойства. так что это больше похоже на крайний случай, который не поддерживается свойствами objc, и он редко бывает полезен или желателен. изменяемый ivar, если это действительно необходимо, обычно должен быть полностью закрытым. в большинстве случаев неизменный - правильный выбор. кроме того, вы часто не хотите сохранять строку, полученную из неизвестного источника; вы захотите скопировать его, потому что он может быть изменяемым.   -  person justin    schedule 16.08.2012


Ответы (2)


Вы правы, copy метод NSMutableString возвращает неизменяемый NSString. Это соглашение в Какао, оно также применяется к NSMutableArray, NSMutableDictionary и т. Д.

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

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

person omz    schedule 16.08.2012
comment
Итак, в основном я должен использовать копию для типов NString, NSArray, NSDictionary, поскольку есть изменяемые варианты, а для изменяемых типов, таких как NSMutableString, NSMutableArray, я должен использовать сохранить. Это правильно? - person rustylepord; 16.08.2012

Первый вопрос, который я хотел бы задать, - как была инициализирована строкаA. Если вы устанавливаете его из простой строки, возможно, именно поэтому вы его получаете. Копирование и сохранение на самом деле работают по-разному, и вы должны знать, зачем использовать тот или иной.

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

person rooster117    schedule 16.08.2012
comment
Я инициализировал его как self.stringA = [NSMutableString new]; - person rustylepord; 16.08.2012
comment
инициализировать его как self.stringA = [[NSMutableString alloc] init]; и посмотрим, изменит ли это что-нибудь - person rooster117; 16.08.2012
comment
new - это просто сокращение от alloc init, они делают то же самое. - person omz; 16.08.2012
comment
Простое сохранение, вероятно, исправит это, как сказал OMZ. - person rooster117; 16.08.2012