2013-03-01 7 views
9

Ho trovato uno strano comportamento con NSString. Ho provato a eseguire il codice seguente e ho notato questo.IOS: versione per NSString non funziona come previsto

NSString *str = [[NSString alloc] initwithstring : @"hello"]; 
[str release]; 
NSLog(@" Print the value : %@", str); 

Qui, nella terza linea l'app dovrebbe bloccarsi perché stiamo accedendo a un oggetto che è stato rilasciato. Ma sta stampando il valore di str. Non sta andando in crash. Ma con NSArray ho osservato un comportamento diverso.

NSArray *array = [[NSArray alloc] initwithobjects : @"1", @"2", nil]; 
[array release]; 
NSLog(@"Print : %@", [array objectatindex : 0]); 
NSLog(@"Print : %@", [array objectatindex : 0]); 

Il codice ha due istruzioni NSLog utilizzate per NSArray. Qui dopo il rilascio quando viene eseguito il primo NSLog, è il valore di stampa. Ma quando viene eseguito il secondo NSLog, l'app si arresta in modo anomalo. Arresto anomalo dell'app è accettabile perché l'array a cui si accede è già stato rilasciato. Ma dovrebbe bloccarsi quando viene eseguito il primo NSLog. Non il secondo.

Aiutatemi con questo comportamento. Come funziona la liberazione in questi casi.

Grazie Jithen

+0

Questo non è un duplicato esatto, ma ho pensato che valesse la pena sottolineare questa domanda poiché ha alcune risposte parzialmente pertinenti: http://stackoverflow.com/questions/8386084/is-allocinitwithstring-same-as-copy –

+0

User @ BoltClock's answer [here] (http://stackoverflow.com/questions/6069459/does-some-text-give-an-autoreleased-or-retain-1-object-back) anche una buona lettura .. – Krishnabhadra

risposta

7

Il primo esempio non si arresta perché i valori letterali stringa non vengono mai rilasciati. Il codice è in realtà:

NSString *str = @"hello"; 
[str release]; 

persone scottarsi con le stringhe sulla gestione della memoria ed erroneamente usando == per confrontarli invece di isEqualToString:. Il compilatore esegue alcune ottimizzazioni che portano a risultati fuorvianti.

Aggiornamento:

Il codice seguente dimostra il mio punto:

NSString *literal = @"foo"; 
    NSString *second = [NSString stringWithString:literal]; 
    NSString *third = [NSString stringWithString:@"foo"]; // <-- this gives a compiler warning for being redundant 
    NSLog(@"literal = %p", literal); 
    NSLog(@"second = %p", second); 
    NSLog(@"third = %p", third); 

Questo codice dà il seguente risultato:

2013-02-28 22: 03: 35,663 SelCast [85617: 11303] letterale = 0x359c
2013-02-28 22: 03: 35.666 SelCast [85617: 11303] secondo = 0x359c
2013/02/28 22: 03: 35,668 SelCast [85617: 11303] = terzo 0x359c

noti che tutti e tre punti variabile sulla stessa memoria.

+0

Questo è interessante .. Hai un riferimento per eseguire il backup? – Krishnabhadra

+0

I valori letterali delle stringhe sono d'accordo. Ma sto allocando memoria all'oggetto NSString. Quindi dovrebbe essere liberato quando viene passato un messaggio di rilascio. Se NSString si comporta in questo modo, allora perché non può NSArray? – Coder

+0

No @jithen, qui in realtà usi init con una stringa letterale, dato che usi '@" ciao "'. Ogni stringa che usa la notazione '@' viene creata in fase di compilazione e ha il suo spazio di memoria ed è costante. il tuo str sta ancora indicando l'indirizzo letterale della stringa anche dopo il rilascio potresti sfuggire al crash dal momento che il letterale non viene rilasciato .. Ma non dipendere mai da questo tipo di comportamento .. – Krishnabhadra

4

Quando si invia un messaggio release su un oggetto, l'oggetto è in realtà non essere rimosso dalla memoria. Il messaggio di rilascio semplicemente decrementa il conteggio dei riferimenti solo di uno. Se il conteggio dei riferimenti è zero, l'oggetto è contrassegnato come libero. Quindi il sistema lo rimuove dalla memoria. Fino a quando questa deallocazione avviene, puoi accedere al tuo oggetto. Anche se si release l'oggetto il puntatore dell'oggetto punta ancora all'oggetto a meno che non si assegni nil al puntatore.

+0

Questo non spiega i diversi risultati tra i due blocchi di codice. E in entrambi i casi, il conteggio dei riferimenti sembra essere 0 immediatamente dopo la chiamata a "rilascio". Quindi, in base alla risposta, entrambi dovrebbero provocare un crash ma solo il secondo lo fa. – rmaddy

+0

Non stavo confrontando entrambi i codici. Ho detto nella seconda parte del codice, per quanto riguarda NSArray, ho usato due istruzioni NSLog una per una. Quando ho provato ad accedere a NSArray, per le prime istruzioni che esegue. Ma per la seconda volta l'app si blocca. – Coder

0

Il primo esempio non si arresta in modo anomalo perché i valori letterali stringa non vengono mai rilasciati. Dove il secondo dipende totalmente dal rilascio e dal contatore di ritenzione.

Read this article. Its contains short-and-sweet explanation for your query

You Should read this apple guideline

+1

Sono d'accordo che è buono per OP leggere le linee guida Apple. Ma per rispondere alla domanda, o si cita la parte pertinente dalle linee guida della mela nella risposta stessa, o si collega alla sezione specifica nelle linee guida. Pubblicare un documento multipagina come risposta non è costruttivo. – Krishnabhadra

6

tuo secondo esempio si blocca al secondo NSLog perché al primo log, la memoria in cui array era non è stato riutilizzato, ma quel primo registro provoca abbastanza attività sul heap per far sì che la memoria venga utilizzata da qualcos'altro. Quindi, quando provi ad accedere di nuovo, si verifica un arresto anomalo.

Ogni volta che un oggetto viene deallocato e la sua memoria contrassegnata come libera, ci sarà un periodo di tempo in cui quella memoria memorizza ancora ciò che rimane di quell'oggetto. Durante questo periodo puoi comunque chiamare metodi su tali oggetti e così via, senza crash. Questa volta è estremamente breve, e se stai facendo un sacco di thread potrebbe non essere nemmeno abbastanza per ottenere il tuo metodo di chiamata. Quindi chiaramente, non fare affidamento su questi dettagli di implementazione per qualsiasi comportamento.

Come altri hanno già detto, per quanto riguarda la prima domanda, i letterali NSString non saranno deallocati. Questo vale per alcune altre classi Foundation (NSNumber) ma è anche un dettaglio di implementazione. Se hai bisogno di fare esperimenti sulla gestione della memoria, usa invece un'istanza NSObject, poiché non mostrerà i comportamenti insoliti.

0

Si presume che release debba distruggere immediatamente l'oggetto. Non penso che sia la garanzia che il linguaggio fa. Che cosa significa release è: Ho finito di usare questo oggetto e prometto di non usarlo di nuovo. Da quel momento in poi spetta al sistema decidere quando distribuire effettivamente la memoria.

Qualsiasi comportamento visualizzato oltre quello non è definito e può cambiare da una versione del runtime Objective C al successivo.

Vale a dire che le altre risposte che suggeriscono la differenza sono stringhe letterali e riutilizzo della memoria sono correntemente corretti ma assumendo che il comportamento sarà sempre come questo sarebbe probabilmente un errore.

Problemi correlati