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.
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.
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"
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.
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 arrayNSArray*newArray2 =[oldArray copy];//Make mutablecopy of arrayNSArray*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 .
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.
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.
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.
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] .
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:
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]
NSArray *array = [mutableArray copy];
NSArray *array = mutableArray;
Antworten:
Copy
macht unveränderliche Kopien. Dies ist sehr nützlich, da Apple verschiedene Optimierungen vornehmen kann. Zum Beispielcopy
behält das Senden an ein unveränderliches Array nur das Objekt bei und gibt es zurückself
.Wenn Sie keine Garbage Collection oder ARC verwenden, denken Sie daran, dass
-copy
das Objekt erhalten bleibt.quelle
copy
ein normales NSArray und kein NSMutableArray erstellt wird?NSArray
&NSMutableArray
,NSString
&NSMutableString
. Aber nicht zum Beispiel,NSViewController
der immer einen veränderlichen Zustand enthält.An
NSMutableArray
ist eine Unterklasse von,NSArray
sodass Sie nicht immer konvertieren müssen. Wenn Sie jedoch sicherstellen möchten, dass das Array nicht geändert werden kann, können Sie eineNSArray
der folgenden Methoden erstellen, je nachdem, ob Sie es automatisch freigeben möchten oder nicht: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.
quelle
Ich mag beide 2 Hauptlösungen:
Oder
Der Hauptunterschied, den ich in ihnen sehe, ist, wie sie sich verhalten, wenn mutableArray gleich Null ist :
quelle
[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.Sie versuchen diesen Code ---
und
quelle
Ziel c
Im Folgenden finden Sie eine Möglichkeit, NSMutableArray in NSArray zu konvertieren:
Schnell
In Swift 3.0 gibt es den neuen Datentyp Array . Deklarieren Sie das Array mit dem
let
Schlüsselwort, dann wird es zu NSArray . Wenn Sie mit demvar
Schlüsselwort deklarieren, wird es zu NSMutableArray .Beispielcode:
quelle
Array
s undNSArray
/NSMutableArray
s. Sie sind nicht gleich.In Ziel-c:
In Kürze:
quelle
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.
quelle
NSMutableArray
zu einerNSArray
Variablen 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.NSMutableArray
Variablen 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 einerNSMutableArray
Variablen zugewiesen und mit Mutationsmethoden aufgerufen wurde, schlagen diese Aufrufe mitdoesNotRespondToSelector
Fehlern fehl , da sich das Objekt befindet, in dem sich der Aufruf der Mutationsmethode befindet Tatsache unveränderlich und reagiert nicht auf diese Methoden.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.
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:
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
quelle
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
quelle