Warum haben gängige Auflistungsklassen in Objective C wie NSString, NSArray, NSDictionary usw. sowohl eine veränderbare als auch eine unveränderbare Version? Welche Logik steckt dahinter, sie getrennt zu definieren? Leistung, Speicherverwaltung oder etwas anderes?
Antworten
Zu viele Anzeigen?Die unveränderlichen Versionen der Klassen existieren, weil ein unveränderliches Objekt an und für sich ein eindeutige Kennung für einen bestimmten Staat . D.h. wenn Sie eine NSArray
von 100 NSString
Instanzen, die NSArray
Instanz kann für jede dieser Zeichenketten als idempotent behandelt werden.
Außerdem bedeutet die Unveränderlichkeit, dass eine Änderung nicht mehr möglich ist, nachdem der Zustand verkauft worden ist. Zum Beispiel, NSView
's subviews
Methode gibt ein unveränderliches Array zurück und stellt damit sicher, dass der Aufrufer keine Spielchen mit dem Inhalt treiben kann (und auch nicht erwartet, dass er das kann). Intern, NSView
könnte wählen, um das [wahrscheinliche] NSMutableArray zurückzugeben, das die Unteransichten enthält (da es intern veränderbar ist) und den Typecast zu NSArray
bedeutet, dass der Aufrufer den Inhalt nicht ohne einen bösen Cast oder eine schlechte Compilerwarnung manipulieren kann. (Dies kann, muss aber nicht die tatsächliche Implementierung sein, aber dieses Muster wird anderswo verwendet).
Unveränderlichkeit bedeutet auch, dass Enumeration und/oder Traversal ohne das Risiko einer Zustandsänderung in der Mitte durchgeführt werden können. In ähnlicher Weise sind viele unveränderliche Klassen auch ausdrücklich thread-sicher; eine beliebige Anzahl von Threads kann den unveränderlichen Zustand gleichzeitig lesen, oft ohne dass eine Sperre erforderlich ist.
Im Allgemeinen für eine API, eine unveränderliche Klasse wird Thread sicher sein, so dass Sie es direkt in einem Hintergrund-Thread lesen können, ohne zu befürchten, dass der Inhalt ändern wird...
Das ist eher für Dinge wie eine Sammlung von Bedeutung, deren Inhalt sich verschieben kann und die Sie vielleicht gerade aufzählen wollen.
Warum haben gängige Auflistungsklassen in Objective C wie NSString, NSArray, NSDictionary usw. sowohl eine veränderbare als auch eine unveränderbare Version?
das konzept wird in verwandten sprachen verwendet. der bemerkenswerte unterschied besteht darin, dass die objc-typen als veränderbare varianten bezeichnet werden. ähnliche sprachen erreichen dies typischerweise durch die anwendung eines schlüsselworts, wie const
Natürlich verwenden auch andere verwandte Sprachen Typen, die ausdrücklich veränderbar oder unveränderbar sind.
Welche Logik steckt dahinter, sie getrennt zu definieren?
objc messaging unterscheidet nicht zwischen const und non-const, und die Sprache bietet keine eingebaute Unterstützung, um sicherzustellen, dass sich der Zustand eines Objekts nicht ändert (obwohl es wirklich keine schwierige Ergänzung wäre, wenn man wirklich geneigt wäre, einen Compiler zu erweitern). also ist auch hier ein bisschen Geschichte im Spiel.
Daher ist es für die Klasse üblich, Unveränderlichkeit und Veränderlichkeit zu definieren und Varianten zu liefern, die die Veränderlichkeit unterscheiden.
Mehrere Abstraktionen führen auch Typsicherheit und Absicht ein.
Leistung
Ja, es gibt mehrere Optimierungen, die ein invariantes Objekt vornehmen kann.
einige Fälle umfassen:
- es könnte Werte zwischenspeichern und sie nie mehr als einmal berechnen.
- es könnte exakte, nicht veränderbare Zuweisungen für seine Daten verwenden.
- Für die Verwendung im Multithreading ist oft kein spezieller Code erforderlich - viele unveränderliche Typen ändern sich nur während der Erstellung bzw. Zerstörung.
- Diese Typen verwenden häufig Klassencluster. Wenn ein Klassencluster implementiert wird, können spezialisierte Implementierungen erhebliche Unterschiede in Bezug auf Speicher, Implementierung usw. aufweisen. So könnte sich eine unveränderliche Zeichenfolge mit genau einem Zeichen von einer veränderlichen Variante unterscheiden.
Speicherverwaltung
einige Fälle umfassen:
- unveränderliche Typen ihren unveränderlichen Inhalt gemeinsam nutzen können.
- Sie können auch die Zuteilungen reduzieren. Zum Beispiel kann eine Implementierung von
copyWithZone:
oinitWithType:
könnte die beibehaltene Quelle zurückgeben, anstatt einer tiefen oder flachen physischen Kopie.
oder etwas anderes?
es macht es einfacher, klare schnittstellen zu schreiben. man kann einige dinge garantieren und (versuchen) einzuschränken. wenn alles veränderbar wäre, gäbe es viel mehr fehler und sonderfälle. tatsächlich könnte die unterscheidung die art und Weise, wie wir an das schreiben von objc-bibliotheken herangehen, völlig verändern:
[[textField stringValue] appendString:@" Hz"];
[textField stateDidChange];
Es ist also schön, dass man Objekte weitergeben kann, ohne sich Sorgen machen zu müssen, dass der Client hinter dem eigenen Rücken Änderungen vornimmt, während man gleichzeitig vermeidet, überall hin zu kopieren.
Wenn man weiß, dass eine Datenstruktur unveränderlich ist, kann man viele Optimierungen vornehmen, die diese Tatsache berücksichtigen. Wenn zum Beispiel ein Array unveränderlich ist, kann man den ganzen Code weglassen, der das Array "wachsen" lassen würde, wenn man versucht, ein Objekt hinzuzufügen, und man kann das unveränderliche Array einfach als Wrapper um ein id[]
.