Wie konvertiere ich NSMutableArray in NSArray?

381

Wie konvertiere ich NSMutableArray in NSArray in ?

marcy
quelle
12
justNSArray *array = [mutableArray copy];
beryllium
1
NSArray *array = mutableArray;
Vladof81
4
Beryllium: Absolut richtig. vladof81: Natürlich nicht.
Gnasher729

Antworten:

511
NSArray *array = [mutableArray copy];

Copymacht unveränderliche Kopien. Dies ist sehr nützlich, da Apple verschiedene Optimierungen vornehmen kann. Zum Beispiel copybehält das Senden an ein unveränderliches Array nur das Objekt bei und gibt es zurück self.

Wenn Sie keine Garbage Collection oder ARC verwenden, denken Sie daran, dass -copydas Objekt erhalten bleibt.

Georg Schölly
quelle
2
Diese Antwort ist großartig, aber wie kann ich anhand der Dokumente erkennen, dass copyein normales NSArray und kein NSMutableArray erstellt wird?
Dan Rosenstark
22
@ Yar: Du siehst die Dokumentation von NSCopying an. Dort heißt es: copyWithZone Die zurückgegebene Kopie ist unveränderlich, wenn die Überlegung „unveränderlich vs. veränderlich“ für das empfangende Objekt gilt. Andernfalls wird die genaue Art der Kopie von der Klasse bestimmt.
Georg Schölly
1
Sehr ordentlich - ich ziehe dies der Lösung von m5h vor. Knapp und effizienter.
David Snabel-Caunt
1
Ich bin damit einverstanden, dass David meine Antwort aktualisiert hat, um auf diese Antwort zu verweisen.
Hallski
2
@Brad: Das bedeutet nur Klassen, die sowohl veränderbare als auch unveränderliche Implementierungen haben. ZB NSArray& NSMutableArray, NSString&NSMutableString . Aber nicht zum Beispiel, NSViewControllerder immer einen veränderlichen Zustand enthält.
Georg Schölly
361

An NSMutableArrayist eine Unterklasse von, NSArraysodass Sie nicht immer konvertieren müssen. Wenn Sie jedoch sicherstellen möchten, dass das Array nicht geändert werden kann, können Sie eine NSArrayder folgenden Methoden erstellen, je nachdem, ob Sie es automatisch freigeben möchten oder nicht:

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

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

EDIT: Die von Georg Schölly bereitgestellte Lösung ist eine bessere Methode und viel sauberer, besonders jetzt, wo wir ARC haben und nicht einmal Autorelease aufrufen müssen.

Hallski
quelle
7
Kann ich einfach (NSArray *) myMutableArray ausführen?
Vojto
2
Ja, da NSMutableArray eine gültige Unterklasse von NSArray ist.
Hallski
4
Das Casting auf (NSArray *) ermöglicht jedoch weiterhin ein Casting auf (NSMutable *). Ist das nicht der Fall?
Sharvey
1
@sharvey: Ja, das ist richtig. Sie erhalten eine Warnung, wenn Sie nicht wirken, sondern einer Unterklasse direkt eine Oberklasse zuweisen. Normalerweise möchten Sie eine unveränderliche Kopie zurückgeben, da nur so sichergestellt werden kann, dass Ihr Array wirklich nicht geändert wird.
Georg Schölly
1
Früher bekannt als "Upcasting" (NSArray *) myMutableArray und das Gegenteil heißt "Downcasting"
Francisco Gutiérrez
113

Ich mag beide 2 Hauptlösungen:

NSArray *array = [NSArray arrayWithArray:mutableArray];

Oder

NSArray *array = [mutableArray copy];

Der Hauptunterschied, den ich in ihnen sehe, ist, wie sie sich verhalten, wenn mutableArray gleich Null ist :

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

NSMutableArray *mutableArray = nil;
NSArray *array = [mutableArray copy];
// array == nil
Richard Venable
quelle
Das ist so falsch. Gerade nachgeguckt. [mutableArray copy] gibt auch ein leeres Array zurück.
Durazno
@ Durazno Es ist nicht falsch. Überprüfen Sie Ihren Test. Wenn [mutableArray copy] ein leeres Array zurückgibt, muss mutableArray ein leeres Array gewesen sein. Meine Antwort gilt nur, wenn mutableArray gleich Null ist.
Richard Venable
Obwohl dies wahr ist, habe ich das Gefühl, dass Sie in Ihrem Beispiel eine grundlegendere Wahrheit vermissen. Da Sie mutableArray als Null zugewiesen haben, [mutableArray copy]kann dies vereinfacht werden [nil copy]. In Ziel-c ist jede an nil gesendete Nachricht immer nil. Es ist wichtig, sich an die Unterscheidung zwischen "nichts" und "einem Array mit nichts" zu erinnern.
Mkirk
@mkirk Lassen Sie uns nicht von der Frage ablenken: "Wie konvertiere ich NSMutableArray in NSArray?" Es gibt zwei primäre Lösungen, und der Hauptunterschied zwischen ihnen besteht darin, wie sie sich verhalten, wenn das veränderbare Array Null ist.
Richard Venable
18

Sie versuchen diesen Code ---

NSMutableArray *myMutableArray = [myArray mutableCopy];

und

NSArray *myArray = [myMutableArray copy];
Jerry Thomsan
quelle
Was macht das, was die anderen nicht machen?
Ben Leggiero
5

Ziel c

Im Folgenden finden Sie eine Möglichkeit, NSMutableArray in NSArray zu konvertieren:

//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;

Schnell

In Swift 3.0 gibt es den neuen Datentyp Array . Deklarieren Sie das Array mit dem letSchlüsselwort, dann wird es zu NSArray . Wenn Sie mit dem varSchlüsselwort deklarieren, wird es zu NSMutableArray .

Beispielcode:

let newArray = oldArray as Array
Sakir Sherasiya
quelle
Der Swift-Teil ist nicht ganz richtig. Siehe hier und hier für den Unterschied zwischen veränderlichen / unveränderlichen Arrays und NSArray/ NSMutableArrays. Sie sind nicht gleich.
Bruno Ely
3

In Ziel-c:

NSArray *myArray = [myMutableArray copy];

In Kürze:

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

Diese [mutableArray copy] Antimuster enthält den gesamten Beispielcode. Beenden Sie dies für wegwerfbare veränderbare Arrays, die vorübergehend sind und am Ende des aktuellen Bereichs freigegeben werden.

Auf keinen Fall könnte die Laufzeit das verschwenderische Kopieren eines veränderlichen Arrays optimieren, das kurz vor dem Verlassen des Gültigkeitsbereichs steht, auf 0 deklariert und endgültig freigegeben wird.

Anton Tropashko
quelle
Das Zuweisen eines NSMutableArrayzu einer NSArrayVariablen wird es nicht verdecken (worum es in der Frage des OP geht). Das Anzeigen eines solchen Werts (z. B. als Rückgabewert oder als Eigenschaft) kann zu sehr schwer zu debuggenden Problemen führen, wenn dieser Wert unerwartet mutiert wird. Dies gilt sowohl für interne als auch für externe Mutationen, da der veränderbare Wert gemeinsam genutzt wird.
David Rönnqvist
Um dieses Array zu mutieren, müssten Sie [NSMutableArray arrayWithArray: ... oder so ähnlich.
Anton Tropashko
Nicht unbedingt. Es reicht aus, es einfach einer NSMutableArrayVariablen zuzuweisen. Da das Objekt nie aufgehört hat, ein veränderbares Array zu sein, ist das Aufrufen von Mutationsmethoden erfolgreich und mutiert die gemeinsam genutzten Daten. Wenn andererseits das ursprüngliche veränderbare Array kopiert und in ein unveränderliches Array geändert und dann einer NSMutableArrayVariablen zugewiesen und mit Mutationsmethoden aufgerufen wurde, schlagen diese Aufrufe mit doesNotRespondToSelectorFehlern fehl , da sich das Objekt befindet, in dem sich der Aufruf der Mutationsmethode befindet Tatsache unveränderlich und reagiert nicht auf diese Methoden.
David Rönnqvist
ok, dies könnte einige Vorteile für Entwickler haben, die die Compiler-Warnung über Tyope-Konvertierungszuweisungen nicht beachten
Anton Tropashko
1

Wenn Sie ein Array über Veränderbarkeit erstellen und dann eine unveränderliche Version zurückgeben möchten, können Sie das veränderbare Array einfach als "NSArray" über Vererbung zurückgeben.

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

    return mutableArray;
}

Wenn Sie dem Aufrufer "vertrauen", dass er das (technisch immer noch veränderbare) Rückgabeobjekt als unveränderliches NSArray behandelt, ist dies eine billigere Option als [mutableArray copy] .

Apple stimmt zu:

Um festzustellen, ob ein empfangenes Objekt geändert werden kann, muss sich der Empfänger einer Nachricht auf den formalen Typ des Rückgabewerts verlassen. Wenn es beispielsweise ein als unveränderlich eingegebenes Array-Objekt empfängt, sollte es nicht versuchen, es zu mutieren . Es ist keine akzeptable Programmierpraxis, anhand seiner Klassenmitgliedschaft festzustellen, ob ein Objekt veränderbar ist.

Die obige Praxis wird hier ausführlicher erörtert:

Best Practice: Geben Sie mutableArray.copy oder mutableArray zurück, wenn der Rückgabetyp NSArray ist

pkamb
quelle
0

Ich war auf der Suche nach der Antwort in Swift 3 und diese Frage wurde als erstes Ergebnis in der Suche angezeigt und ich werde von der Antwort inspiriert, also hier ist der Swift 3-Code

let array: [String] = nsMutableArrayObject.copy() as! [String]
Amr wütend
quelle