Sind NSStrings auf dem Heap oder auf dem Stack gespeichert und was ist eine gute Möglichkeit, einen zu initialisieren?

8

Ich habe zwei neue Fragen:

1) Betrachte diese Zeile:

%Vor%

Es gab zwei Dinge, die ich gelernt habe, aber ich möchte eine Bestätigung: Wie ich gelernt habe, zeigt die Nachricht "alloc" an, dass die Instanz von NSString im "Heap" Speicher gespeichert wird. Ich habe auch verstanden, dass primitive Variablen wie "chars" im "stack" Speicher gespeichert sind.

Bedeutet das:

  • Die Instanz von NSString wird im Heap-Speicher gespeichert.
  • UND dass dieses Objekt einen iVar-Zeiger (wenn die initWithString -Methode aufgerufen wurde) auf die "Value" -String von primitiven "chars", die sich im Stack-Speicher befinden, hat? Wie funktioniert das in Wirklichkeit?

Die zweite Frage ist direkt verwandt und verursacht für mich ein persönliches Dilemma (wahrscheinlich weil ich einen Punkt verpasse): 2) Welchen der beiden Ansätze würdest du konsultieren und warum ?:

%Vor%

Wenn meine erste Frage bestätigt wird, sollten beide Ansätze "am Ende" auf Zeichen zeigen, die im Stapelspeicher gespeichert sind. Ich sehe daher eigentlich nicht den Zweck, die erste Option zu verwenden und sich um die Retain-Zählung zu kümmern.

    
Trace 11.09.2011, 04:12
quelle

2 Antworten

13

Kurze Antwort: In diesem Fall haben beide Zeilen das gleiche Ergebnis. Es ist in Ordnung, die String-Konstante direkt myString zuzuweisen.

Längere Antwort:

Es stimmt, dass Objective-C-Objekte auf dem Heap zugewiesen sind. Es ist jedoch nicht wahr, dass "primitive" Werte immer auf dem Stapel gespeichert sind. Lokale Variablen werden auf dem Stapel gespeichert, unabhängig davon, ob sie primitiv sind oder nicht. (Sie können zum Beispiel eine lokale Variable deklarieren, die eine Struktur ist, die nicht als primitiv betrachtet wird.) Sie können Grundwerte auf dem Heap speichern, aber die einzige Möglichkeit, in diesem Fall auf sie zuzugreifen, ist über einen Zeiger. Zum Beispiel:

%Vor%

Der Grund, dass wir immer Zeiger verwenden, um auf Objective-C-Objekte zu verweisen, ist, dass Objekte immer auf dem Heap zugewiesen werden. Wenn Sie etwas auf dem Stapel speichern möchten, muss der Compiler seine Größe kennen. In Objective-C ist die Größe eines Objekts nicht bekannt, bis das Programm tatsächlich ausgeführt wird.

Also, zurück zu deinen Strings. Versuchen Sie, die folgenden zwei Zeilen auszuführen:

%Vor%

Wenn Sie nach der zweiten Zeile brechen, finden Sie, dass foo und bar die gleiche Adresse enthalten; Das heißt, sie zeigen auf dasselbe Objekt. Da NSString-Objekte unveränderlich sind, wird beim Erstellen eines Objekts mit einer konstanten Zeichenfolge nur ein Zeiger auf diese Konstante zurückgegeben.

Warum gibt es sogar einen -initWithString: in NSString, wenn das alles ist? NSString ist ein "Klassencluster", was bedeutet, dass NSString die öffentliche Schnittstelle zu mehreren verschiedenen internen Klassen ist. Wenn Sie einen NSString *, der keine Konstante ist, an -initWithString: übergeben, ist das zurückgelieferte Objekt möglicherweise eine Instanz einer anderen Klasse als die, die Sie erhalten, wenn Sie die Konstante verwenden. Als Klassencluster versteckt NSString eine Menge von Implementierungsdetails von Ihnen, so dass Sie eine gute Leistung für verschiedene Stringtypen erhalten, ohne sich darum kümmern zu müssen, wie alles funktioniert.

    
Caleb 11.09.2011, 04:55
quelle
4

NSString s sind interessant, weil sie bis vor kurzem der einzige Typ von Objective-C-Objekten waren, die als Literal bereitgestellt werden konnten. Die Blockobjekte, die in iOS 4 und OS X 10.6 hinzugefügt wurden, sind die anderen neueren Erweiterungen, die mir bekannt sind, aber sie haben ihre eigenen besonderen Regeln, weshalb ich das nur der Vollständigkeit halber erwähne.

C-Primitive können im Heap oder im Stack gespeichert werden. Zum Beispiel:

%Vor%

Die meisten Objective-C-Objekte können nur auf dem Heap gespeichert werden. Sie haben recht damit zu sagen, dass alloc eine neue Kopie eines Objekts auf dem Heap liefert, und das Ergebnis Ihres Aufrufs myString besteht darin, einen Zeiger auf einen NSString auf dem Heap zu haben.

Die Syntax @"" ist jedoch eine Abkürzung für das Erstellen eines Objekts. @"Value" erstellt tatsächlich ein Objektliteral. So könnten Sie beispielsweise Folgendes tun:

%Vor%

Und die Ausgabe wäre "alue". Sie können die Nachricht substringFromIndex: an @"Value" senden, da es sich um ein literales Objekt handelt.

Was NSString mit initWithString: genau macht ist eine Implementierung, aber Sie können sicher sein, dass es eine Kopie der Sache braucht, auf die verwiesen wird, wenn es nötig ist. Sonst würden Sie seltsames Verhalten sehen, wenn Sie so etwas tun würden:

%Vor%

Sie brauchen sich also keine Gedanken über die Lebensdauer von allem zu machen, was Sie ihm übergeben. Es ist NSString 's Job, damit umzugehen.

In der Praxis laufen NSString Objektliterale niemals wirklich ab, so dass der Punkt ein wenig unklar ist. Wenn Sie jedoch initWithUTF8String: oder etwas anderes verwendet hätten, das ein C-Literal verwendet und das C-Literal auf dem Stapel war, müssten Sie sich trotzdem keine Sorgen machen, weil NSString damit umgehen würde.

Als Antwort auf Ihre zweite Frage würde ich die zweite Version bevorzugen, weil sie kürzer ist und daher deutlicher zeigt, was Sie vorhaben. Es gibt einige theoretische Leistungsvorteile für Letzteres - insbesondere, wenn Sie an mehreren Stellen das gleiche Literal verwenden - aber sie sind so unglaublich vernachlässigbar, dass sie heutzutage nicht in Betracht gezogen werden sollten.

    
Tommy 11.09.2011 04:37
quelle