Когда -copy возвращает изменяемый объект? - PullRequest
9 голосов
/ 27 августа 2011

Я прочитал в Какао и Цель C: Включение и запуск , что -copy всегда будет возвращать неизменный объект, а -mutableCopy всегда будет возвращать изменяемый объект:

Важно знать, что вызов -copy для изменяемого объекта возвращает неизменяемую версию.Если вы хотите скопировать изменяемый объект и сохранить изменчивость в новой версии, вы должны вызвать -mutableCopy для оригинала.Это полезно, хотя, потому что если вы хотите «заморозить» изменяемый объект, вы можете просто вызвать -copy на нем.

Так что у меня есть что-то вроде этого:

Согласно этому предыдущему ответу :

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

Это выглядит несколько изолированным для NSURLRequest, посколькуNSArray действует так, как задумано:

NSArray *arr = [[NSMutableArray alloc] init];
NSLog( @"%@", [arr className] );                 // __NSArrayM
NSLog( @"%@", [[arr copy] className] );          // __NSAraryI
NSLog( @"%@", [[array mutableCopy] className] ); // __NSArrayM

Итак ...

  1. Когда -copy возвращает неизменный объект (как и ожидалось) и когда он возвращает изменяемый объект?
  2. Как добиться ожидаемого эффекта получения «замороженной» копии изменяемого объекта, который отказывается быть «замороженным»?

Ответы [ 4 ]

13 голосов
/ 27 августа 2011

Я думаю, что вы обнаружили большой разрыв между документацией и реальностью.

Заявка на документацию протокола NSCopying:

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

Но в некоторых случаях это явно неправильно, как вы показали в своих примерах (и я отправил им отзыв об этом через эту страницу документации).

Но (# 2), на мой взгляд, это на самом деле не имеет значения, и вам все равно.

Смысл -copy в том, что он вернет объект, который вы можете использовать с гарантией того, что он будет вести себя независимо от оригинала. Это означает, что если у вас есть изменяемый объект, -copy и изменить исходный объект, копия не увидит эффект. (В некоторых случаях, я думаю, это означает, что -copy можно оптимизировать, чтобы ничего не делать, потому что, если объект неизменен, его нельзя изменить в первую очередь. Я могу ошибаться по этому поводу. (Мне сейчас интересно что это значит для ключей словаря из-за этого, но это отдельная тема ...))

Как вы видели, в некоторых случаях новый объект может действительно иметь изменяемый класс (даже если документация говорит нам, что это не так). Но до тех пор, пока вы не полагаетесь на его изменчивость (с чего бы это?), Это не имеет значения.

Что делать? Всегда обрабатывайте результат -copy как неизменный , просто так.

3 голосов
/ 27 августа 2011

1) Когда -copy возвращает неизменный объект (как и ожидалось) и когда он возвращает изменяемый объект?

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

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

2) Как добиться ожидаемого эффекта от получения «замороженной» копии изменяемого объекта, который отказывается быть «замороженным»?

хороший способ использовать конструктор копирования неизменяемого класса (аналог ответа St3fan).как и copy, это не гарантия.

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

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

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

1 голос
/ 27 августа 2011

Имейте в виду, что не существует одной copy реализации - каждый класс реализует свою собственную.И, как мы все знаем, реализация среды выполнения Objective C немного «дурная», в некоторых местах.Поэтому я думаю, что мы можем сказать, что в основном copy возвращает неизменяемую версию, но существуют некоторые исключения.

(Кстати, что это делает:

NSArray *arr = [[NSMutable array] init];

?)

0 голосов
/ 27 августа 2011

Лучший способ превратить объект в изменчивый - это использовать изменяемый конструктор. Как например:

NSArray* array = ...;
NSMutableArray* mutableArray = [NSMutableArray arrayWithArray: array];

Копирование используется для создания копии объекта. Не менять его изменчивость.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...