Какова логика наличия изменяемых и неизменяемых версий классов, таких как NSArray, NSDictionary и т. д., в Objective C?

Почему общие классы коллекций в Objective C, такие как NSString, NSArray, NSDictionary и т. д., имеют как изменяемую, так и неизменную версию. Какова логика определения их отдельно? Производительность, управление памятью или что-то еще?


person NSExplorer    schedule 04.07.2011    source источник


Ответы (5)


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

Кроме того, неизменность означает, что изменение не может произойти после того, как состояние было продано. Например, метод subviews NSView возвращает неизменяемый массив, таким образом гарантируя, что вызывающая сторона не будет играть в игры с содержимым (и даже не ожидает, что сможет). Внутренне NSView может выбрать возврат [вероятного] NSMutableArray, который содержит подпредставления (поскольку он является внутренне изменяемым), а приведение типа к NSArray означает, что вызывающая сторона не может манипулировать содержимым без злого приведения или плохого предупреждение компилятора. (Это может быть или не быть реальной реализацией, кстати, но этот шаблон используется в другом месте).

Неизменяемость также означает, что перечисление и/или обход могут выполняться без риска изменения состояния в середине. Точно так же многие неизменяемые классы также являются потокобезопасными; любое количество потоков может одновременно считывать неизменное состояние, часто без необходимости блокировки.

person bbum    schedule 04.07.2011

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

Это имеет большее значение для таких вещей, как коллекция, содержимое которой может меняться, и вы можете быть в процессе их перечисления.

person Kendall Helmstetter Gelner    schedule 04.07.2011
comment
Тот факт, что объект неизменяем, не означает, что операции над объектом являются потокобезопасными. Это происходит с некоторыми из самых простых объектов в Foundation, таких как NSString, но это связано с реализацией, а не с контрактом. - person Ryan; 04.07.2011
comment
Теоретически верно, но, как правило, единственная причина, по которой кто-то разделяет изменяемые и неизменяемые версии класса, заключается в том, что они хотят потокобезопасности — иначе почему бы не придерживаться простоты наличия изменяемой версии? Можете ли вы привести какие-либо примеры, когда неизменяемые классы были созданы для широкого использования, но не были потокобезопасными? - person Kendall Helmstetter Gelner; 04.07.2011
comment
Собственно, потокобезопасность неизменяемых NS коллекций и неизменяемых NSString задокументирована (но, да, неизменность, в общем, не означает потокобезопасность). Существует множество примеров неизменяемых объектов, которые не являются потокобезопасными из-за особенностей внутренней реализации (таких как заполнение кеша). - person bbum; 04.07.2011
comment
Я понял, что моя первоначальная формулировка была слишком сильной - я согласен с тем, что неизменность не является гарантией потокобезопасности, как я заявил в своем неожиданном ответе. Поэтому я отредактировал его с некоторыми оговорками. Но я все еще чувствую, что никогда не сталкивался с API, где что-то, что имело неизменяемые/изменяемые варианты, не имело неизменяемый вариант потокобезопасности. Конечно, есть много кода, написанного людьми, где что-то, что оказывается неизменяемым, не является потокобезопасным, но это отличается от чего-то, разделенного на неизменяемый/изменяемый, где много мыслей уходит на разделение и причины, почему. - person Kendall Helmstetter Gelner; 04.07.2011
comment
Еще одна хорошая особенность неизменяемых объектов заключается в том, что вы можете делиться ими беспорядочно; так как они не меняются (ну не на контрактном уровне) никого не удивишь. Изменяемые объекты должны иметь свою собственную идентичность, и с ними нужно быть гораздо осторожнее. - person Donal Fellows; 05.07.2011

Почему общие классы коллекций в Objective C, такие как NSString, NSArray, NSDictionary и т. д., имеют как изменяемую, так и неизменную версию.

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

Какова логика определения их отдельно?

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

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

несколько абстракций также вводят безопасность типов и намерение.

Представление

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

некоторые случаи включают:

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

управление памятью

некоторые случаи включают:

  • неизменяемые типы могут делиться своим неизменяемым содержимым.
  • они также могут сократить ассигнования. например, реализация copyWithZone: или initWithType: может возвращать сохраненный исходный код, а не глубокую или поверхностную физическую копию.

или что-нибудь еще?

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

[[textField stringValue] appendString:@" Hz"];
[textField stateDidChange];

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

person justin    schedule 04.07.2011

По сути, когда вы знаете, что структура данных неизменяема, вы можете сделать множество оптимизаций вокруг этого. Например, если массив является неизменяемым, вы можете исключить весь код, который будет «растить» массив всякий раз, когда вы пытаетесь добавить объект, и вы можете просто сделать свой неизменяемый массив оболочкой вокруг id[].

person Dave DeLong    schedule 04.07.2011
comment
По сути, неизменяемые классы могут иметь своего рода бонус эффективности по сравнению с аналогичными изменяемыми классами. - person Itai Ferber; 04.07.2011

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

Благодарность

person Deepankar_Parashar    schedule 17.04.2017