Подтвердить что ты не робот

Лучшая практика: возвращайте mutableArray.copy или mutableArray, если тип возврата - NSArray

- (NSArray *)map:(id (^)(id))block {
    NSEnumerator * enumerator = self.objectEnumerator;
    NSMutableArray * array    = [NSMutableArray array];
    id obj;
    while ((obj = enumerator.nextObject)) {
        [array addObject:(block(obj) ?: [NSNull null])];
    }
    return array (NSMutableArray *); or return array.copy (NSArray *)
}

Это категория в NSArray

4b9b3361

Ответ 1

В данном коде изменяемый массив создается только для возврата. Он не проводится на постоянной основе ничем другим. Поэтому нет никакой опасности для его прямого возвращения.

Существуют две основные опасности при возврате изменяемого массива, который продолжает удерживаться возвращаемым кодом:

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

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

Ответ 2

В этом случае вам не нужно копировать.

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

Только интерфейс указывает, что он возвращает NSArray *, поэтому, пока он возвращает вид NSArray *, он удовлетворяет требованию. Возвращает ли он MyCustomArray * или NSMutableArray * чисто детали реализации, он не будет иметь никакого эффекта в представлении точки вызова.

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

Ответ 3

От Получение разрешенных объектов:

Использовать тип возврата, а не интроспекцию

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

[...]

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

Вообще говоря:

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

  • Если вы не знаете, может ли вызывающий абонент не следовать этим рекомендациям, и вы хотите защищать код, верните неизменяемую копию, используя array.copy.

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

Ответ 4

Это зависит от типа возвращаемого метода. Если ваш тип возвращаемого значения является неизменным, используйте копию или mutableCopy.

Ответ 5

В большинстве случаев нет необходимости создавать копию, поскольку вы не держите другую ссылку на array вне метода.

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

Компилятор будет защищать вас, не позволяя вам напрямую обращаться к мутационным сообщениям в возвращенном NSArray, но это не мешает вам просто набрасывать __NSArrayM на NSMutableArray или выполнять мутационные селекторы на объекте и минуя компилятор. Вызов мутационного сообщения на __NSArrayI приведет к сбою приложения, поэтому, если вы хотите гарантировать эту безопасность, вызов copy по возврату - это путь.