Рекомендация. Возвращайте 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
5 ответов
От получения изменяемых объектов:
Используйте тип возврата, а не самоанализ
Чтобы определить, может ли он изменить полученный объект, получатель сообщения должен полагаться на формальный тип возвращаемого значения. Если он получает, например, объект массива, типизированный как неизменяемый, он не должен пытаться изменить его. Неприемлемой практикой программирования является определение того, является ли объект изменчивым, основываясь на его принадлежности к классу.
[...]
Вы не должны делать предположения о том, является ли объект изменчивым, основываясь на членстве в классе. Ваше решение должно основываться исключительно на том, что подпись метода, торгующего объект, говорит о его изменчивости. Если вы не уверены, является ли объект изменчивым или неизменным, предположите, что он неизменный.
Вообще говоря:
Если ваш собеседник следует этим рекомендациям, просто верните изменяемый массив, так как он немного дешевле, и вызывающий не будет его изменять.
Если вы не уверены, что вызывающий абонент может не следовать этим рекомендациям, и хотите защитить код, верните неизменную копию, используя
array.copy
,
В данном случае это не имеет значения, поскольку, даже если вызывающий объект мутирует, вы никогда больше не будете использовать этот экземпляр массива.
В этом случае вам не нужно копировать.
Объект массива создается локально, поэтому он не может быть неожиданно изменен чем-то другим.
Интерфейс только указать, что он возвращает NSArray *
до тех пор, пока он возвращает вид NSArray *
, он удовлетворил требование. Вернется ли это MyCustomArray *
или же NSMutableArray *
это просто детали реализации, это не повлияет на точку зрения вызывающей стороны.
Однако, если объект массива является общим, вам необходимо вернуть его копию. В противном случае неизменное предположение о NSArray
может быть сломан и вызвать неожиданное поведение.
В данном коде изменяемый массив создается только для возврата. Это не проводится на постоянной основе ничем другим. Поэтому нет никакой опасности в том, чтобы вернуть его напрямую.
Существует две основные опасности при возвращении изменяемого массива, который продолжает удерживаться возвращаемым кодом:
- Код владельца будет видоизменяться, пока вызывающая сторона содержит ссылку. Массив изменяется, когда вызывающая сторона не ожидала этого.
- Вызывающая сторона изменяет массив (даже если это не так, потому что он был возвращен как неизменяемый тип, и вызывающая сторона должна это учитывать). Из-за кода массива-владельца из-под него произошла ошибка.
Таким образом, если метод возвращает изменяемый массив, на который он продолжает хранить ссылку, он, вероятно, должен вернуть копию.
В большинстве случаев нет необходимости создавать копию, поскольку у вас нет другой ссылки на array
вне метода.
Однако следует учитывать, что под капотом эти объекты разные. Если вы напечатаете объекты в отладчике, вы обнаружите, что один __NSArrayM
в то время как другой __NSArrayI
,
Компилятор защитит вас, не позволив вам вызывать мутационные сообщения на возвращаемый NSArray
напрямую, но это не мешает вам просто разыграть __NSArrayM
в NSMutableArray
или выполнение мутационных селекторов на объекте и обход компилятора. Вызов мутационного сообщения на __NSArrayI
вызовет сбой приложения, поэтому, если вы хотите гарантировать эту безопасность, позвоните copy
на обратном пути это путь.
Это зависит от вашего типа возврата метода. Если ваш возвращаемый тип неизменен, используйте copy или mutableCopy.