¿Cómo convierto NSMutableArray a NSArray?

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.

Georg Schölly
fuente
2
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.

hallski
fuente
77
¿Puedo hacer (NSArray *) myMutableArray?
Vojto
2
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"
Francisco Gutiérrez
113

Me gustan las dos soluciones principales:

NSArray *array = [NSArray arrayWithArray:mutableArray];

O

NSArray *array = [mutableArray copy];

La principal diferencia que veo en ellos es cómo se comportan cuando mutableArray es nulo :

NSMutableArray *mutableArray = nil;
NSArray *array = [NSArray arrayWithArray:mutableArray];
// array == @[] (empty array)

NSMutableArray *mutableArray = nil;
NSArray *array = [mutableArray copy];
// array == nil
Richard Venable
fuente
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.
Richard Venable
18

intentas este código ---

NSMutableArray *myMutableArray = [myArray mutableCopy];

y

NSArray *myArray = [myMutableArray copy];
Jerry Thomsan
fuente
¿Qué hace esto que los demás no hacen?
Ben Leggiero
5

C objetivo

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 array
NSArray *newArray2 = [oldArray copy];

//Make mutablecopy of array
NSArray *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 .

Código de muestra:

let newArray = oldArray as Array
Sakir Sherasiya
fuente
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.
Bruno Ely
3

En el objetivo-c:

NSArray *myArray = [myMutableArray copy];

En rápido:

 var arr = myMutableArray as NSArray
Vikram Biwal
fuente
2
NSArray *array = mutableArray;

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.

Anton Tropashko
fuente
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.

- (NSArray *)arrayOfStrings {
    NSMutableArray *mutableArray = [NSMutableArray array];
    mutableArray[0] = @"foo";
    mutableArray[1] = @"bar";

    return mutableArray;
}

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:

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í:

Mejor práctica: Devuelva mutableArray.copy o mutableArray si el tipo de retorno es NSArray

pkamb
fuente
0

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]
Amr enojado
fuente