NSMutableString как сохранить / скопировать

У меня есть NSMutableString в моем приложении (почти 10-11); все определены как ivar / property

@property (nonatomic, retain) NSMutableString *str1; 

Я где-то читал, что лучше использовать «копию» для строк. Это правда? Если да, могу ли я просто заменить сохранение для копирования в своем приложении и удалить выпуск в dealloc?

Нужно ли мне также рассмотреть некоторые другие вещи?

Кроме того, нормально ли иметь 10-11 NSMutableString в 1 приложении. Я имею в виду использование памяти? У меня также есть 4-5 NSMutableDictionary, а также в моем приложении. Пожалуйста, дайте мне знать, если все в порядке.

(примечание: конкретный ответ NSMutableString – это путь вниз)

У меня есть NSMutableString в моем приложении (почти 10-11); все определены как ivar / property

@property (nonatomic, retain) NSMutableString *str1; Я где-то читал, что лучше использовать «копию» для строк. Это правда?

да, копирование NSString (не говоря уже о NSMutableString еще) должно быть по умолчанию. причина (как утверждается другими плакатами) заключается в том, что реализация неизменяемого экземпляра может просто retain себя при реализации copyWithZone: Кроме того, copy дает вам ожидаемое поведение. другими словами, нет смысла сохранять строку, если она на самом деле неизменяема. чтобы гарантировать, что вы имеете дело с неизменяемой строкой, вы просто копируете при создании и настройке.

Если да, могу ли я просто заменить сохранение для копирования в своем приложении и удалить выпуск в dealloc?

copy , как и retain возвращает объект, который вы должны явно освободить (например, в dealloc) в среде, не связанной с мусором. неизменяемые строки по-прежнему подсчитываются. есть исключения из этого, в частности:

  • Для продолжительности программы существуют литералы CF / NS-String

  • вы можете использовать CF-API для создания строк, которые никогда не выпускаются или управляются за пределами традиционных механизмов сохранения / выпуска

  • Подclassы NS-Type могут реализовывать другую схему (хотя обычные соображения этого являются ошибочными)

Нужно ли мне также рассмотреть некоторые другие вещи?

теперь мы переходим к деталям типа NSMutable. реализация синтаксиса свойств вызывает copy . как известно, -[NSMutableString copy] возвращает неизменяемый NSString. это проблема, ожидающая появления наивной реализации, поскольку ваш NAR-файл NSMutableString теперь является NSString, используя стандартизованную реализацию сеттера.

 @property (nonatomic, retain) NSMutableString *str1;` // or @property (nonatomic, copy) NSMutableString *str1;` 

при объявлении:

  @property (nonatomic, retain) NSMutableString *str1;` 

вы можете использовать синтезированную реализацию по умолчанию.

но есть поворот при объявлении:

  @property (nonatomic, copy) NSMutableString *str1;` 

вы не должны использовать синтезированную реализацию по умолчанию. вместо этого вы должны написать свой собственный :

 - (void)setStr1:(NSMutableString *)arg { /* locking/observing/undo/etc omitted */ NSMutableString * copy = [arg mutableCopy]; NSMutableString * prev = str1; str1 = copy; [prev release]; } - (NSMutableString *)str1 { /* locking/observing/etc omitted */ /* don't return something the clients thinks they may possibly modify, and don't return something you may modify behind their back */ return [[str1 mutableCopy] autorelease]; // -- or??? return [[str1 retain] autorelease]; } 

хм … это не очень понятно и не очень важно для клиентов. это также подразумевает много ненужных вещей и вводит дополнительные накладные расходы. давайте переоценим это.

дополнительные соображения / проблемы на данный момент:

  • установщик по умолчанию требует, чтобы клиент сделал mutableCopy строки, если они содержат только неизменяемую строку. который сразу же превращается в уникальную копию вами, в сеттер, поскольку вы не можете ожидать, что клиент создаст уникальный mutableCopy только для вас – кроме того, это обязанность реализации classа. поэтому NSMutableString – плохой аргумент для установщика. NSString – соответствующий наборщик, если вы не сохраните строку.

  • NSMutableString также является неоднозначным getter – см. Реализацию. он копирует + autorelease или сохраняет + autorelease? нет стандартного ожидания для общей формы. Кроме того, клиенты могут зависеть от одного конкретного поведения. это действительно деталь реализации classа, если вы не имеете дело с плотно связанными объектами. тесно связанными объектами являются те, которые в основном являются зависимыми друг от друга, и обычно не могут использоваться повторно в других контекстах. эта концепция в порядке, вы можете просто использовать частный class по нескольким причинам. в любом случае семантика copy / write для внешних клиентов и подclassов не является (неявно) понятной, а реализация опасна.

  • использование NSMutableString обычно плохое. NSMutableString не является streamобезопасным. для клиентов не имеет никакого доступа к доступу и мутации строки – это опасно. любой дизайн, который разделяет объекты, которые не являются streamобезопасными, следует рассматривать с осторожностью. совместное использование в этом случае также распространяется на использование подclassа (поэтому сделайте его @private , где это возможно)

  • сохранение также, как правило, плохой дизайн – клиенты не будут знать, когда строка была (или будет) изменена извне, если вы не добавите эквивалентный внешний код для поддержки этого.

  • в зависимости от того, как используется интерфейс, это также может привести к большому количеству ненужного копирования. бу.

ОК – теперь мы довольно убеждены, что наше «улучшение» по-прежнему плохое в большинстве случаев =), как мы можем улучшить дизайн?

вы должны, помимо исключительных случаев тесно связанных объектов, объявить / реализовать свое имущество следующим образом:

 @interface MONThing : NSObject { @private NSMutableString * str1; } /* note: passes/returns NSString */ @property (nonatomic, copy) NSString * str1; @end @implementation MONThing // no need for clients to create a mutableCopy - (void)setStr1:(NSString *)arg { /* locking/observing/undo/etc omitted */ NSMutableString * copy = [arg mutableCopy]; NSMutableString * prev = str1; str1 = copy; [prev release]; } // the result is clearly defined. return a copy for // thread-safety, expected behavior, and to minimize // further copies when handling the result. - (NSString *)str1 { /* locking/observing/etc omitted */ /* don't return something the clients thinks they may possibly modify, and don't return something you may modify behind their back */ return [[str1 copy] autorelease]; } @end 

ваш интерфейс теперь улучшен, правильнее, требует меньше документации и работает лучше.

вы также можете удалить общедоступные средства доступа, если они вам не нужны.

мы можем жить с этим интерфейсом, где это необходимо.

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

как упоминалось ранее, NSMutableString не является streamобезопасным, во многих случаях проще и эффективнее использовать (скопированный) NSString ivar, когда ваша строка мала или не изменяется часто. добавив изменяемую строку к интерфейсу (как указано выше), вы должны будете гарантировать безопасность streamа вручную. во многих случаях оптимально делать что-то в этом направлении:

 @interface MONThing : NSObject { NSString * str1; } @property (nonatomic, copy) NSString * str1; @end @implementation MONThing @synthesize str1; - (void)updateTimeElapsed:(NSTimeInterval)seconds { NSMutableString * s = [NSMutableString stringWithFormat:@"%f seconds", seconds]; /* ...some mutations... */ self.str1 = s; } @end 

конечно, будет несколько исключений из этого – там, где вам понадобится mutable ivar, но лучше всего использовать неизменные ivars, где это возможно, и где сомневайтесь, вместо того, чтобы вводить тонну сложности streamов. в большинстве случаев вы можете удалить использование изменяемых строк из интерфейсов и при необходимости построить строки (как показано выше).

С другой стороны, коллекции (NSMutableArray, NSMutableDictionary, NSMutableSet и т. д.) требуются чаще всего в реализациях и в целом более сложны.

удачи!

Хотя ответ Taskinoor правильный, я хотел бы добавить немного больше объяснений.

Рекомендация – использовать копию для classов, которые являются частью кластера classов, которые имеют изменяемые / неизменяемые пары; таких как NSString / NSMutableString NSArray / NSMutableArray NSDictionary / NSMutableDictionary NSSet / NSMutableSet

Причина этого заключается в том, что возможно иметь свойство, объявленное как неизменяемый тип (например, NSString), но передающее ему изменяемый тип (например, NSMutableString). В этом случае можно изменить свойство вне classа, как описывает Taskinoor.

Рекомендуется использовать copy , потому что она ведет себя разумно с classовыми кластерами. отправка copy в изменяемый class возвращает неизменяемую копию объекта (т.е. отправка сообщения copy в NSMutableString возвращает NSString ). Но отправка copy неизменяемому экземпляру эквивалентна отправке сообщения retain .

Для изменяемой строки copy и сохранения имеют другой результат. Если вы сделаете копию str1 на str2, любое изменение на str1 не отразится на str2, и любое изменение в str2 не будет отображаться в str1, так как они являются отдельным объектом. Но если str1 сохраняется в str2, то оба ссылаются на один и тот же изменяемый строковый объект, а изменение через str1 будет отображаться в str2. Но NSString не изменяет. Таким образом, для простой строки (то есть не изменяемой строки) копия просто увеличивает счетчик ссылок, что означает, что она внутренне обрабатывается как сохранение (я не уверен на 100% относительно обработки копии, как сохранение для не изменяемых объектов, но видел это на Так в другом вопросе. Googling, я отредактирую, если найду ссылку.).

И если вы используете копию, вам все равно нужно освободить ее в dealloc.

Наличие 10 – 11 строк нормального размера не должно отрицательно влиять на использование памяти. Типичное приложение может содержать гораздо больше строк. По нормальному размеру я подразумеваю, что вы не добавляете 1 миллион символов в строку. Это будет серьезной проблемой. Память, взятая строкой, будет увеличиваться по мере увеличения длины строки. То же самое касается словаря. Память, занимаемая словарем, будет зависеть от того, что вы храните в словаре. Сам словарь не имеет больших накладных расходов. Вы всегда можете проверить использование памяти в своем приложении с помощью инструмента.

  • UIPageViewController не возвращает никаких распознавателей жестов в iOS 6
  • Метод доступа после завершения анимации UIImageView
  • UIPopoverController для iphone не работает?
  • Удалить HTML-tags из NSString на iPhone
  • Данные перезагрузки UITableView
  • Получение времени, прошедшего в Objective-C
  • Сравнение двух NSDates и игнорирование временной составляющей
  • API, чтобы определить, работает ли на iPhone или iPad
  • Как найти причину ошибки «double free» malloc?
  • Создайте эскиз или изображение AVPlayer в текущее время
  • Координаты текстуры OpenGL в пиксельном пространстве
  • Давайте будем гением компьютера.