berilio: absolutamente correcto. vladof81: Por supuesto que no.
gnasher729
Respuestas:
511
NSArray*array=[mutableArray copy];
Copyhace copias inmutables Esto es bastante útil porque Apple puede hacer varias optimizaciones. Por ejemplo, enviar copya una matriz inmutable solo retiene el objeto y lo devuelve self.
Si no usa recolección de basura o ARC recuerde que -copyretiene el objeto.
esta respuesta es excelente, pero ¿cómo puedo deducir de los documentos que copycrea un NSArray normal y no un NSMutableArray?
Dan Rosenstark
22
@Yar: Usted mira la documentación de NSCopying. Allí dice: copyWithZone La copia devuelta es inmutable si la consideración "inmutable vs. mutable" se aplica al objeto receptor; de lo contrario, la clase determina la naturaleza exacta de la copia.
Georg Schölly
1
Muy ordenado: prefiero esto a la solución de m5h. Ambos concisos y más eficientes.
David Snabel-Caunt
1
Estoy de acuerdo con David, actualicé mi respuesta para señalar esta respuesta.
Hallski
2
@Brad: Eso solo significa clases que tienen implementaciones tanto mutables como inmutables. Por ejemplo, NSArrayy NSMutableArray, NSStringy NSMutableString. Pero no, por ejemplo, NSViewControllerque siempre contiene un estado mutable.
Georg Schölly
361
Una NSMutableArrayes una subclase de, NSArraypor lo que no siempre necesitará convertir, pero si desea asegurarse de que la matriz no se puede modificar, puede crear una NSArrayde estas formas dependiendo de si desea que se lance automáticamente o no:
/* Not autoreleased */NSArray*array=[[NSArray alloc] initWithArray:mutableArray];/* Autoreleased array */NSArray*array=[NSArray arrayWithArray:mutableArray];
EDITAR: La solución proporcionada por Georg Schölly es una mejor manera de hacerlo y mucho más limpia, especialmente ahora que tenemos ARC y ni siquiera tenemos que llamar a autorelease.
Sí, ya que NSMutableArray es una subclase de NSArray que es válida.
Hallski
44
Sin embargo, la conversión a (NSArray *) todavía permite una copia de seguridad a (NSMutable *). ¿No es ese el caso?
sharvey
1
@harvey: Sí, eso es correcto. Recibirás una advertencia si no lanzas pero asignas una superclase a una subclase directamente. Por lo general, desea devolver una copia inmutable, porque esa es la única manera de asegurarse de que su matriz realmente no se modificará.
Georg Schölly
1
Anteriormente eso se conoce como "Upcasting" (NSArray *) myMutableArray y el inverso se llama "Downcasting"
Esto esta muy mal. Acabo de revisarlo. [copia de matriz mutable] también devuelve una matriz vacía.
durazno
@durazno No está mal. Vuelva a verificar su prueba. Si [copia mutableArray] devuelve una matriz vacía, entonces mutableArray debe haber sido una matriz vacía. Mi respuesta solo se aplica cuando mutableArray es nulo.
Richard Venable
Aunque esto es cierto, siento que te estás perdiendo una verdad más fundamental en tu ejemplo. Como ha asignado mutableArray para que sea nulo, [mutableArray copy]puede simplificarse a [nil copy]. En el objetivo-c, cualquier mensaje enviado a nil siempre será nil. Es importante recordar la distinción entre "nada" y "una matriz que no contiene nada".
mkirk
@mkirk No distraigamos de la pregunta en cuestión: "¿Cómo convierto NSMutableArray a NSArray?" Hay 2 soluciones principales, y la principal diferencia entre ellas es cómo se comportan cuando la matriz mutable es nula.
A continuación se muestra la forma de convertir NSMutableArray a 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;
Rápido
En Swift 3.0 hay un nuevo tipo de datos Array . Declarar Array usando la letpalabra clave, entonces se convertiría en NSArray Y si declara usar la varpalabra clave, entonces se convertirá en NSMutableArray .
La parte Swift no es del todo correcta. Vea aquí y aquí la diferencia entre mutable / inmutable Arraysy NSArray/ NSMutableArrays. Ellos no son los mismos.
Esta [mutableArray copy] antipatrón está en todo el código de muestra. Deje de hacerlo para arreglos mutables desechables que son transitorios y se desasignan al final del alcance actual.
No hay forma de que el tiempo de ejecución pueda optimizar la copia innecesaria de una matriz mutable que está a punto de quedar fuera de alcance, decrementada a 0 y desasignada para siempre.
Asignar una NSMutableArraya una NSArrayvariable no la convertirá (de eso se trata la pregunta del OP). Exponer dicho valor (por ejemplo, como un valor de retorno o como una propiedad) podría resultar en problemas muy difíciles de depurar si ese valor fue mutado inesperadamente. Esto se aplica a las mutaciones internas y externas ya que el valor mutable se comparte.
David Rönnqvist
Para mutar esa matriz tendrías que [NSMutableArray arrayWithArray: ... o algo así.
Anton Tropashko
No necesariamente. Simplemente asignarlo a una NSMutableArrayvariable es suficiente. Dado que el objeto nunca dejó de ser una matriz mutable, invocar métodos de mutación tendrá éxito y mutará los datos compartidos. Si, por otro lado, se copió la matriz mutable original (cambiándola a una matriz inmutable) y luego se la asignó a una NSMutableArrayvariable y se le solicitaron métodos de mutación, esas llamadas fallarían con doesNotRespondToSelectorerrores porque el objeto que recibió la llamada al método de mutación está en hecho inmutable y no responde a esos métodos.
David Rönnqvist
ok, esto podría tener algún mérito para los desarrolladores que no prestan atención a la advertencia del compilador sobre las asignaciones de conversión de tyope
Anton Tropashko
1
Si está construyendo una matriz a través de la mutabilidad y luego desea devolver una versión inmutable, simplemente puede devolver la matriz mutable como un "NSArray" a través de la herencia.
Si "confía" en la persona que llama para tratar el objeto devuelto (técnicamente aún mutable) como un NSArray inmutable, esta es una opción más barata que [mutableArray copy].
Para determinar si puede cambiar un objeto recibido, el receptor de un mensaje debe confiar en el tipo formal del valor de retorno. Si recibe, por ejemplo, un objeto de matriz escrito como inmutable, no debe intentar mutarlo . No es una práctica de programación aceptable determinar si un objeto es mutable en función de su pertenencia a clases.
La práctica anterior se analiza con más detalle aquí:
estaba buscando la respuesta en swift 3 y esta pregunta se mostró como primer resultado en la búsqueda y me inspiró la respuesta, así que aquí está el código de swift 3
let array:[String]= nsMutableArrayObject.copy() as![String]
NSArray *array = [mutableArray copy];
NSArray *array = mutableArray;
Respuestas:
Copy
hace copias inmutables Esto es bastante útil porque Apple puede hacer varias optimizaciones. Por ejemplo, enviarcopy
a una matriz inmutable solo retiene el objeto y lo devuelveself
.Si no usa recolección de basura o ARC recuerde que
-copy
retiene el objeto.fuente
copy
crea un NSArray normal y no un NSMutableArray?NSArray
yNSMutableArray
,NSString
yNSMutableString
. Pero no, por ejemplo,NSViewController
que siempre contiene un estado mutable.Una
NSMutableArray
es una subclase de,NSArray
por lo que no siempre necesitará convertir, pero si desea asegurarse de que la matriz no se puede modificar, puede crear unaNSArray
de estas formas dependiendo de si desea que se lance automáticamente o no:EDITAR: La solución proporcionada por Georg Schölly es una mejor manera de hacerlo y mucho más limpia, especialmente ahora que tenemos ARC y ni siquiera tenemos que llamar a autorelease.
fuente
Me gustan las dos soluciones principales:
O
La principal diferencia que veo en ellos es cómo se comportan cuando mutableArray es nulo :
fuente
[mutableArray copy]
puede simplificarse a[nil copy]
. En el objetivo-c, cualquier mensaje enviado a nil siempre será nil. Es importante recordar la distinción entre "nada" y "una matriz que no contiene nada".intentas este código ---
y
fuente
C objetivo
A continuación se muestra la forma de convertir NSMutableArray a NSArray:
Rápido
En Swift 3.0 hay un nuevo tipo de datos Array . Declarar Array usando la
let
palabra clave, entonces se convertiría en NSArray Y si declara usar lavar
palabra clave, entonces se convertirá en NSMutableArray .Código de muestra:
fuente
Array
syNSArray
/NSMutableArray
s. Ellos no son los mismos.En el objetivo-c:
En rápido:
fuente
Esta
[mutableArray copy]
antipatrón está en todo el código de muestra. Deje de hacerlo para arreglos mutables desechables que son transitorios y se desasignan al final del alcance actual.No hay forma de que el tiempo de ejecución pueda optimizar la copia innecesaria de una matriz mutable que está a punto de quedar fuera de alcance, decrementada a 0 y desasignada para siempre.
fuente
NSMutableArray
a unaNSArray
variable no la convertirá (de eso se trata la pregunta del OP). Exponer dicho valor (por ejemplo, como un valor de retorno o como una propiedad) podría resultar en problemas muy difíciles de depurar si ese valor fue mutado inesperadamente. Esto se aplica a las mutaciones internas y externas ya que el valor mutable se comparte.NSMutableArray
variable es suficiente. Dado que el objeto nunca dejó de ser una matriz mutable, invocar métodos de mutación tendrá éxito y mutará los datos compartidos. Si, por otro lado, se copió la matriz mutable original (cambiándola a una matriz inmutable) y luego se la asignó a unaNSMutableArray
variable y se le solicitaron métodos de mutación, esas llamadas fallarían condoesNotRespondToSelector
errores porque el objeto que recibió la llamada al método de mutación está en hecho inmutable y no responde a esos métodos.Si está construyendo una matriz a través de la mutabilidad y luego desea devolver una versión inmutable, simplemente puede devolver la matriz mutable como un "NSArray" a través de la herencia.
Si "confía" en la persona que llama para tratar el objeto devuelto (técnicamente aún mutable) como un NSArray inmutable, esta es una opción más barata que
[mutableArray copy]
.Apple está de acuerdo:
La práctica anterior se analiza con más detalle aquí:
Mejor práctica: Devuelva mutableArray.copy o mutableArray si el tipo de retorno es NSArray
fuente
estaba buscando la respuesta en swift 3 y esta pregunta se mostró como primer resultado en la búsqueda y me inspiró la respuesta, así que aquí está el código de swift 3
fuente