2011-09-11 8 views
8

Ho 2 nuove domande:Sono NSStrings memorizzati sul mucchio o sullo stack e quello che è un buon modo per inizializzare un

1) considerano questa linea:

NSString *myString = [[NSString alloc] initWithString: @"Value"]; 

C'erano due cose che ho imparato, ma vorrei conferma: Come ho appreso, il messaggio "alloc" indica che l'istanza di NSString sarà memorizzata nella memoria "heap". Ho capito anche che le variabili primitive come "char" sono memorizzate nella memoria "stack".

Questo significa che:

  • l'istanza di NSString viene memorizzato nella memoria heap;
  • E che questo oggetto ha un puntatore iVar (quando è stato chiamato il metodo initWithString) alla stringa "Valore" di "caratteri" primitivi, che risiedono nella memoria dello stack? Come funziona in realtà?

La seconda domanda è direttamente correlata e causa per me un dilemma personale (probabilmente perché mi manca un punto): 2) Quale dei due approcci vuoi consultare e perché ?:

NSString *myString = [[NSString alloc] initWithString: @"Value"]; 
NSString *myString = @"Value"; 

Se la mia prima domanda è confermata, entrambi gli approcci dovrebbero "alla fine" puntare ai caratteri che sono memorizzati nella memoria dello stack. Pertanto, in realtà non vedo lo scopo di utilizzare la prima opzione e di essere infastidito dal conteggio dei ritiri.

risposta

13

Risposta breve: In questo caso, entrambe le linee hanno lo stesso risultato È bene assegnare la costante di stringa direttamente a myString.

Più rispondere:

E 'vero che gli oggetti Objective-C sono allocati sul mucchio. Non è vero, però, che i valori "primitivi" sono sempre memorizzati nello stack. Le variabili locali sono memorizzate nello stack, indipendentemente dal fatto che siano primitive o meno. (È possibile, ad esempio, dichiarare una variabile locale che è una struct, che non è considerata primitiva.) È possibile memorizzare i valori primitivi sull'heap, ma l'unico modo per accedervi in ​​quel caso è tramite un puntatore. Ad esempio:

int *someInt = malloc(sizeof(int)); // allocate a block of memory to hold an int 
*someInt = 42;      // store data in that memory 

Il motivo per cui sempre uso puntatori a riferiamo oggetti Objective-C è che gli oggetti sono sempre allocati sul mucchio. Se vuoi archiviare qualcosa nello stack, il compilatore deve conoscere la sua dimensione. In Objective-C, la dimensione di un oggetto non è nota fino a quando il programma non è in esecuzione.

Quindi, torna alle tue corde. Provare a eseguire le seguenti due righe:

NSString *foo = [[NSString alloc] initWithString:@"foo"]; 
NSString *bar = @"foo"; 

Se si interrompe dopo la seconda linea, vi accorgerete che foo e bar contengono lo stesso indirizzo; cioè, puntano allo stesso oggetto. Poiché gli oggetti NSString sono immutabili, la creazione di uno con una stringa costante restituisce semplicemente un puntatore a tale costante.

Perché c'è anche un -initWithString: in NSString se è tutto ciò che fa? NSString è un "class cluster", ovvero NSString è l'interfaccia pubblica per diverse classi interne. Se si passa un NSString * che non è una costante in -initWithString:, l'oggetto che si ottiene potrebbe essere un'istanza di una classe diversa da quella che si ottiene quando si utilizza la costante. Come cluster di classe, NSString nasconde molti dettagli di implementazione da te in modo da ottenere buone prestazioni per diversi tipi di stringhe senza doversi preoccupare di come tutto funzioni.

4

NSString s sono interessanti perché fino a poco tempo fa erano l'unico tipo di oggetto Objective-C che poteva essere fornito come letterale. Gli oggetti a blocchi aggiunti in iOS 4 e OS X 10.6 sono l'altra aggiunta recente di cui sono a conoscenza, ma hanno le loro regole particolari, quindi ne parlo solo per completezza.

Le primitive C possono essere memorizzate nell'heap o nella pila. Ad esempio:

- (void)someMethod 
{ 
    int i = 3; // i is on the stack 
} 

- (void)someOtherMethod 
{ 
    int *i = (int *)malloc(sizeof(int)); // i now points to an 'int' on the heap 
} 

La maggior parte degli oggetti Objective-C può essere memorizzata solo nell'heap. Hai ragione nel dire che alloc fornisce una nuova copia di un oggetto sull'heap e il risultato della tua chiamata myString sarà di avere un puntatore a un NSString nell'heap.

Tuttavia, la sintassi @"" è una scorciatoia per la creazione di un oggetto. @"Value" crea effettivamente un oggetto letterale. Quindi, per esempio, potresti fare:

NSLog(@"%@", [@"Value" substringFromIndex:1]); 

E l'uscita sarebbe "alore". È possibile inviare il messaggio substringFromIndex: a @"Value" perché è un oggetto letterale.

Esattamente quello che NSString fa con initWithString: è un'implementazione specifica ma si può essere certi che richiederà una copia dell'oggetto puntato se necessario. In caso contrario, si vedrebbe comportamento strano se hai fatto qualcosa di simile:

NSMutableString *mutableString = [NSMutableString stringWithString:@"String"]; 
NSString *immutableString = [NSString stringWithString:mutableString]; 

[mutableString appendString:@" + hat"]; 

// immutableString would now have mutated if it was simply 
// keeping a reference to the string passed in 

Voi dunque non è necessario preoccuparsi della vita di qualsiasi cosa si passa ad esso. È il lavoro di NSString a occuparsene.

In pratica, i letterali degli oggetti NSString non scadono mai, quindi il punto è un po 'discutibile. Se comunque avessi usato initWithUTF8String: o qualcos'altro che prendesse un letterale C, e che il letterale C fosse in pila, non avresti ancora nulla di cui preoccuparti perché lo avrebbe fatto NSString.

In risposta alla tua seconda domanda, preferirei la seconda versione con la motivazione che è più breve e quindi dimostra più chiaramente cosa intendi fare. Ci sono alcuni vantaggi teorici in termini di prestazioni per quest'ultimo - specialmente se si utilizza lo stesso valore letterale in più punti - ma sono così incredibilmente trascurabili da non meritarli di essere considerati al giorno d'oggi.

Problemi correlati