Copyделает неизменные копии. Это очень полезно, потому что Apple может делать различные оптимизации. Например, отправка copyв неизменяемый массив только сохраняет объект и возвращает self.
Если вы не используете сборщик мусора или ARC, помните, что -copyсохраняет объект.
этот ответ copyхорош , но как я могу узнать из документов, которые создают обычный NSArray, а не NSMutableArray?
Дэн Розенстарк
22
@Yar: Вы просматриваете документацию NSCopying. Там говорится: copyWithZone. Возвращаемая копия является неизменной, если к получающему объекту применяется соображение «неизменяемый и изменяемый»; в противном случае точный характер копии определяется классом.
Георг Шолли
1
Очень аккуратно - я предпочитаю это решению m5h. И кратко и более эффективно.
Дэвид Снабель-Каунт
1
Я согласен, Дэвид, обновил мой ответ, чтобы указать на этот ответ.
hallski
2
@Brad: Это просто означает, что классы имеют как изменяемые, так и неизменные реализации. Например, NSArray& NSMutableArray, NSString& NSMutableString. Но не например, NSViewControllerкоторый всегда содержит изменяемое состояние.
Георг Шолли
361
An NSMutableArrayявляется подклассом, NSArrayтак что вам не всегда нужно конвертировать, но если вы хотите убедиться, что массив не может быть изменен, вы можете создать NSArrayлюбой из этих способов в зависимости от того, хотите ли вы, чтобы он был автоматически освобожден или нет:
/* Not autoreleased */NSArray*array=[[NSArray alloc] initWithArray:mutableArray];/* Autoreleased array */NSArray*array=[NSArray arrayWithArray:mutableArray];
РЕДАКТИРОВАТЬ: Решение, предоставленное Георгом Schölly, является лучшим способом сделать это и намного чище, особенно теперь, когда у нас есть ARC и даже не нужно вызывать autorelease.
Могу ли я просто сделать (NSArray *) myMutableArray?
Войто
2
Да, поскольку NSMutableArray является действующим подклассом NSArray.
hallski
4
Однако приведение к (NSArray *) все еще позволяет приведение обратно к (NSMutable *). Разве это не так?
Шарви
1
@sharvey: Да, это правильно. Вы получите предупреждение, если не будете разыгрывать, а назначаете суперкласс непосредственно подклассу. Обычно вы хотите вернуть неизменяемую копию, потому что это единственный способ убедиться, что ваш массив действительно не будет изменен.
Георг Шолли
1
Ранее это называлось «Upcasting» (NSArray *) myMutableArray, а обратное называется «Downcasting»
Это так неправильно. Только что проверил. [mutableArray copy] также возвращает пустой массив.
Дуразно
@durazno Это не так. Дважды проверьте свой тест. Если [mutableArray copy] возвращает пустой массив, тогда mutableArray должен был быть пустым массивом. Мой ответ применяется только тогда, когда mutableArray равен нулю.
Ричард Венейбл
Хотя это правда, я чувствую, что вы упускаете более фундаментальную истину в своем примере. Поскольку вы присвоили mutableArray значение nil, [mutableArray copy]его можно упростить до [nil copy]. В target-c любое сообщение, отправленное на ноль, всегда будет ноль. Важно помнить различие между «ничем» и «массивом, в котором ничего нет».
Mkirk
@mkirk Давайте не будем отвлекаться от вопроса: «Как мне преобразовать NSMutableArray в NSArray?» Существует 2 основных решения, и основное различие между ними заключается в том, как они ведут себя, когда изменяемый массив равен нулю.
Ниже приведен способ преобразования NSMutableArray в NSArray:
//oldArray is having NSMutableArray data-type.//Using Init with Array method.NSArray*newArray1 =[[NSArray alloc]initWithArray:oldArray];//Make copy of arrayNSArray*newArray2 =[oldArray copy];//Make mutablecopy of arrayNSArray*newArray3 =[oldArray mutableCopy];//Directly stored NSMutableArray to NSArray.NSArray*newArray4 = oldArray;
стриж
В Swift 3.0 появился новый тип данных Array . Объявите массив с помощью letключевого слова, тогда он станет NSArray. А если объявите с помощью varключевого слова, то он станет NSMutableArray .
Часть Swift не совсем верна. Смотрите здесь и здесь для различия между изменяемыми / неизменяемыми Arrays и NSArray/ NSMutableArrays. Они не одинаковы.
Этот [mutableArray copy]антипаттерн есть во всем примере кода. Прекратите делать это для одноразовых изменяемых массивов, которые являются временными и освобождаются в конце текущей области.
Нет способа, которым среда выполнения могла бы оптимизировать бесполезное копирование изменяемого массива, который вот-вот выйдет из области видимости, уменьшится до 0 и будет освобожден навсегда.
Присвоение NSMutableArrayк NSArrayпеременной не тайному его (что вопрос в OP составляет около). Предоставление такого значения (например, в качестве возвращаемого значения или в качестве свойства) может привести к очень сложным проблемам отладки, если это значение было неожиданно изменено. Это относится как к внутренним, так и к внешним мутациям, поскольку изменяемое значение является общим.
Дэвид Ренквист
Чтобы изменить этот массив, вам нужно [NSMutableArray arrayWithArray: ... или что-то в этом роде.
Антон Тропашко
Не обязательно. Достаточно просто присвоить его NSMutableArrayпеременной. Поскольку объект никогда не переставал быть изменяемым массивом, вызов методов с мутацией для него завершится успешно и приведет к изменению общих данных. Если, с другой стороны, исходный изменяемый массив был скопирован, изменив его на неизменяемый массив, а затем назначен NSMutableArrayпеременной и вызвав методы мутации, эти вызовы завершатся ошибкой, doesNotRespondToSelectorпоскольку объект, получивший вызов метода мутации, находится в факт неизменен и не отвечает на эти методы.
Дэвид Ренквист,
хорошо, это может быть полезно разработчикам, которые не обращают внимания на предупреждение компилятора о настройках преобразования тиопов
Антон Тропашко
1
Если вы создаете массив с помощью изменчивости, а затем хотите вернуть неизменяемую версию, вы можете просто вернуть изменяемый массив как «NSArray» через наследование.
Если вы «доверяете» вызывающей стороне для обработки (технически все еще изменяемого) возвращаемого объекта как неизменяемого NSArray, это более дешевый вариант, чем [mutableArray copy].
Чтобы определить, может ли он изменить полученный объект, получатель сообщения должен полагаться на формальный тип возвращаемого значения. Если он получает, например, объект массива, типизированный как неизменяемый, он не должен пытаться изменить его . Неприемлемой практикой программирования является определение того, является ли объект изменчивым, основываясь на его принадлежности к классу.
Вышеуказанная практика обсуждается более подробно здесь:
NSArray *array = [mutableArray copy];
NSArray *array = mutableArray;
Ответы:
Copy
делает неизменные копии. Это очень полезно, потому что Apple может делать различные оптимизации. Например, отправкаcopy
в неизменяемый массив только сохраняет объект и возвращаетself
.Если вы не используете сборщик мусора или ARC, помните, что
-copy
сохраняет объект.источник
copy
хорош , но как я могу узнать из документов, которые создают обычный NSArray, а не NSMutableArray?NSArray
&NSMutableArray
,NSString
&NSMutableString
. Но не например,NSViewController
который всегда содержит изменяемое состояние.An
NSMutableArray
является подклассом,NSArray
так что вам не всегда нужно конвертировать, но если вы хотите убедиться, что массив не может быть изменен, вы можете создатьNSArray
любой из этих способов в зависимости от того, хотите ли вы, чтобы он был автоматически освобожден или нет:РЕДАКТИРОВАТЬ: Решение, предоставленное Георгом Schölly, является лучшим способом сделать это и намного чище, особенно теперь, когда у нас есть ARC и даже не нужно вызывать autorelease.
источник
Мне нравятся оба основных решения:
Или
Основное различие я вижу в них , как они ведут себя , когда mutableArray равна нулю :
источник
[mutableArray copy]
его можно упростить до[nil copy]
. В target-c любое сообщение, отправленное на ноль, всегда будет ноль. Важно помнить различие между «ничем» и «массивом, в котором ничего нет».вы попробуйте этот код ---
а также
источник
Objective-C
Ниже приведен способ преобразования NSMutableArray в NSArray:
стриж
В Swift 3.0 появился новый тип данных Array . Объявите массив с помощью
let
ключевого слова, тогда он станет NSArray. А если объявите с помощьюvar
ключевого слова, то он станет NSMutableArray .Образец кода:
источник
Array
s иNSArray
/NSMutableArray
s. Они не одинаковы.В объективе-c:
В скором времени:
источник
Этот
[mutableArray copy]
антипаттерн есть во всем примере кода. Прекратите делать это для одноразовых изменяемых массивов, которые являются временными и освобождаются в конце текущей области.Нет способа, которым среда выполнения могла бы оптимизировать бесполезное копирование изменяемого массива, который вот-вот выйдет из области видимости, уменьшится до 0 и будет освобожден навсегда.
источник
NSMutableArray
кNSArray
переменной не тайному его (что вопрос в OP составляет около). Предоставление такого значения (например, в качестве возвращаемого значения или в качестве свойства) может привести к очень сложным проблемам отладки, если это значение было неожиданно изменено. Это относится как к внутренним, так и к внешним мутациям, поскольку изменяемое значение является общим.NSMutableArray
переменной. Поскольку объект никогда не переставал быть изменяемым массивом, вызов методов с мутацией для него завершится успешно и приведет к изменению общих данных. Если, с другой стороны, исходный изменяемый массив был скопирован, изменив его на неизменяемый массив, а затем назначенNSMutableArray
переменной и вызвав методы мутации, эти вызовы завершатся ошибкой,doesNotRespondToSelector
поскольку объект, получивший вызов метода мутации, находится в факт неизменен и не отвечает на эти методы.Если вы создаете массив с помощью изменчивости, а затем хотите вернуть неизменяемую версию, вы можете просто вернуть изменяемый массив как «NSArray» через наследование.
Если вы «доверяете» вызывающей стороне для обработки (технически все еще изменяемого) возвращаемого объекта как неизменяемого NSArray, это более дешевый вариант, чем
[mutableArray copy]
.Apple соглашается:
Вышеуказанная практика обсуждается более подробно здесь:
Рекомендация. Возвращайте mutableArray.copy или mutableArray, если тип возвращаемого значения - NSArray.
источник
я искал ответ в swift 3, и этот вопрос был показан в качестве первого результата поиска, и меня вдохновляет ответ, поэтому вот код swift 3
источник