Come posso convertire NSMutableArray in NSArray?


Risposte:


511
NSArray *array = [mutableArray copy];

Copyfa copie immutabili. Questo è abbastanza utile perché Apple può apportare varie ottimizzazioni. Ad esempio, l'invio copya un array immutabile conserva solo l'oggetto e restituisce self.

Se non usi la garbage collection o ARC ricorda che -copyconserva l'oggetto.


2
questa risposta è ottima, ma come posso dirlo dai documenti che copycreano un normale NSArray e non un NSMutableArray?
Dan Rosenstark,

22
@Yar: guardi la documentazione di NSCopying che indica lì: copyWithZone La copia restituita è immutabile se il corrispettivo “immutabile vs. mutabile” si applica all'oggetto ricevente; altrimenti la natura esatta della copia è determinata dalla classe.
Georg Schölly,

1
Molto pulito: preferisco questo alla soluzione di m5h. Sia conciso che più efficiente.
David Snabel-Caunt,

1
Sono d'accordo David, ho aggiornato la mia risposta per indicare questa risposta.
hallski,

2
@Brad: questo significa solo classi che hanno implementazioni sia mutabili che immutabili. Ad esempio NSArray& NSMutableArray, NSString& NSMutableString. Ma non per esempio NSViewControllerche contiene sempre uno stato mutabile.
Georg Schölly,

361

Una NSMutableArrayè una sottoclasse di NSArrayquindi non sarà sempre necessario convertirla, ma se si desidera assicurarsi che l'array non possa essere modificato, è possibile creare NSArrayuno di questi modi a seconda che si desideri rilasciare automaticamente o meno:

/* Not autoreleased */
NSArray *array = [[NSArray alloc] initWithArray:mutableArray];

/* Autoreleased array */
NSArray *array = [NSArray arrayWithArray:mutableArray];

EDIT: La soluzione fornita da Georg Schölly è un modo migliore per farlo e molto più pulito, soprattutto ora che abbiamo ARC e non abbiamo nemmeno bisogno di chiamare il rilascio automatico.


7
Posso semplicemente fare (NSArray *) myMutableArray?
Vojto,

2
Sì, poiché NSMutableArray è una sottoclasse di NSArray valida.
hallski,

4
Tuttavia, il cast su (NSArray *) consente comunque di eseguire il backup su (NSMutable *). Non è così?
sharvey,

1
@sharvey: Sì, è corretto. Riceverai un avviso se non esegui il cast ma assegni direttamente una superclasse a una sottoclasse. Di solito, si desidera restituire una copia immutabile, poiché è l'unico modo per essere sicuri che l'array non verrà modificato.
Georg Schölly,

1
Precedentemente è noto come "Upcasting" (NSArray *) myMutableArray e l'inverso è chiamato "Downcasting"
Francisco Gutiérrez

113

Mi piacciono entrambe le 2 soluzioni principali:

NSArray *array = [NSArray arrayWithArray:mutableArray];

O

NSArray *array = [mutableArray copy];

La differenza principale che vedo in loro è come si comportano quando mutableArray è nullo :

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

NSMutableArray *mutableArray = nil;
NSArray *array = [mutableArray copy];
// array == nil

Questo è così sbagliato. Ho appena controllato. [mutableArray copy] restituisce anche un array vuoto.
Durazno,

@durazno Non è sbagliato. Ricontrolla il tuo test. Se [copia mutableArray] restituisce un array vuoto, allora mutableArray deve essere stato un array vuoto. La mia risposta si applica solo quando mutableArray è zero.
Richard Venable,

Anche se questo è vero, sento che ti manca una verità più fondamentale nel tuo esempio. Poiché hai assegnato mutableArray a zero, [mutableArray copy]può essere semplificato [nil copy]. Nell'obiettivo-c qualsiasi messaggio inviato a zero sarà sempre zero. È importante ricordare la distinzione tra "niente" e "una matrice senza niente".
mkirk,

@mkirk Non distraggiamoci dalla domanda: "Come posso convertire NSMutableArray in NSArray?" Esistono 2 soluzioni primarie e la differenza principale tra loro è il modo in cui si comportano quando l'array mutabile è zero.
Richard Venable,

18

prova questo codice ---

NSMutableArray *myMutableArray = [myArray mutableCopy];

e

NSArray *myArray = [myMutableArray copy];

Cosa fa questo che gli altri non fanno?
Ben Leggiero,

5

Objective-C

Di seguito è riportato il modo per convertire NSMutableArray in 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;

veloce

In Swift 3.0 è disponibile un nuovo tipo di dati Array . Dichiara array utilizzando la letparola chiave, quindi diventerà NSArray E se dichiari l'utilizzo della varparola chiave, diventa NSMutableArray .

Codice di esempio:

let newArray = oldArray as Array

La parte Swift non è del tutto corretta. Vedi qui e qui per la differenza tra mutabile / immutabile Arrays e NSArray/ NSMutableArrays. Non sono gli stessi.
Bruno Ely,

3

Nell'obiettivo-c:

NSArray *myArray = [myMutableArray copy];

In breve tempo:

 var arr = myMutableArray as NSArray

2
NSArray *array = mutableArray;

Questo [mutableArray copy]antipattern è in tutto il codice di esempio. Smettere di farlo per gli array mutabili usa e getta che sono transitori e vengono deallocati alla fine dell'ambito corrente.

Non è possibile che il runtime ottimizzi la copia dispendiosa di un array mutabile che sta per uscire dall'ambito di applicazione, decrefatto su 0 e deallocato per sempre.


L'assegnazione di una NSMutableArraya una NSArrayvariabile non la convertirà (che è la domanda del PO). L'esposizione di tale valore (ad esempio come valore restituito o come proprietà) potrebbe comportare problemi molto difficili da eseguire il debug se tale valore è stato inaspettatamente mutato. Questo vale sia per le mutazioni interne che esterne poiché il valore mutabile è condiviso.
David Rönnqvist,

Per mutare quell'array dovresti [NSMutableArray arrayWithArray: ... o qualcosa del genere.
Anton Tropashko,

Non necessariamente. Basta assegnarlo a una NSMutableArrayvariabile è sufficiente. Dato che l'oggetto non ha mai smesso di essere un array mutabile, la chiamata a metodi di muting su di esso avrà successo e trasformerà i dati condivisi. Se d'altra parte l'array mutabile originale fosse copiato - cambiandolo in un array immutabile - e quindi assegnato a una NSMutableArrayvariabile e avessero richiamato metodi di muting, quelle chiamate fallirebbero con doesNotRespondToSelectorerrori perché l'oggetto che ha ricevuto la chiamata del metodo mutating è in fatto immutabile e non risponde a questi metodi.
David Rönnqvist,

ok, questo potrebbe avere dei meriti per gli sviluppatori che non tengono conto dell'avvertimento del compilatore riguardo alle assegnazioni di conversione tyope
Anton Tropashko,

1

Se stai costruendo un array tramite la mutabilità e vuoi restituire una versione immutabile, puoi semplicemente restituire l'array mutabile come "NSArray" tramite l'ereditarietà.

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

    return mutableArray;
}

Se "ti fidi" del chiamante per trattare l'oggetto restituito (tecnicamente ancora mutabile) come un NSArray immutabile, questa è un'opzione più economica di [mutableArray copy].

Apple consente:

Per determinare se è possibile modificare un oggetto ricevuto, il destinatario di un messaggio deve fare affidamento sul tipo formale del valore restituito. Se riceve, ad esempio, un oggetto array digitato come immutabile, non dovrebbe tentare di mutarlo . Non è una pratica di programmazione accettabile determinare se un oggetto è mutabile in base alla sua appartenenza alla classe.

La pratica di cui sopra è discussa in modo più dettagliato qui:

Procedura consigliata: restituire mutableArray.copy o mutableArray se il tipo restituito è NSArray


0

stavo cercando la risposta in Swift 3 e questa domanda è stata mostrata come primo risultato nella ricerca e mi sono ispirata la risposta da essa, quindi ecco il codice Swift 3

let array: [String] = nsMutableArrayObject.copy() as! [String]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.