2013-01-02 4 views
9

Eventuali duplicati:
Why do weak NSString properties not get released in iOS?Objective-C: attritube debole non funzionano come previsto

Sono un novizio di Objective C e ho alcune domande che mi non posso rispondere a me stesso Ho un blocco di codice per la variabile test __weak (sto usando ARC, ovviamente):

NSString *myString = [[NSString alloc] initWithFormat:@"John"]; 
NSString * __weak weakString = myString; 
myString = nil; //<-- release the NSString object 
NSLog(@"string: %@", weakString); 

L'uscita dei codici di cui sopra è come previsto, poiché weakString è una variabile debole:

2013-01-02 11:42:27.481 ConsoleApp[836:303] string: (null) 

Ma quando ho modificato il codice a questo:

NSString *myString = [[NSString alloc] initWithFormat:@"John"]; 
NSString * __weak weakString = myString; 
NSLog(@"Before: %@", weakString); //<--- output to see if the __weak variable really works. 
myString = nil; 
NSLog(@"After: %@", weakString); 

l'uscita non è del tutto quello che mi aspettavo:

012.351.641.061.
2013-01-02 11:46:03.790 ConsoleApp[863:303] Before: John 
2013-01-02 11:46:03.792 ConsoleApp[863:303] After: John 

L'output di quest'ultimo NSLog deve essere stato (nil) anziché "John". Ho provato a cercare in molti documenti ma non ho trovato la risposta per questo caso. Qualcuno può dare una spiegazione ragionevole? Grazie in anticipo.

+0

@jrturton: Non penso che questo sia un duplicato della domanda collegata. Il problema era l'utilizzo di una costante 'NSString' che non partecipava alla solita gestione della memoria a causa delle ottimizzazioni delle prestazioni. Il poster qui usa 'initWithFormat' per evitare esattamente questo problema. – zoul

+0

Ho letto (ma non ho potuto trovare questa volta) un altro dupe di questo in cui l'ottimizzazione di NSString impedisce questo funzionamento. Se l'OP tenta un diverso tipo di oggetto, sospetto che tutto funzioni come previsto. Continuerò a cercare ... – jrturton

+0

Anche qui: http://stackoverflow.com/questions/9202810/lifetime-of-weak-local-variables-with-arc – jrturton

risposta

6

La funzione NSLog mantiene la NSString passata in un pool autorelease. Pertanto, la variabile di azzeramento-debole non verrà azzerata fino a quando il pool di autorelease non si sarà esaurito. Ad esempio:

__weak NSString* weakString = nil; 

@autoreleasepool { 
    NSString* myString = [[NSString alloc] initWithFormat:@"Foo"]; // Retain count 1 
    weakString = myString;   // Retain count 1 
    NSLog(@"A: %@", weakString); // Retain count 2 
    NSLog(@"B: %@", weakString); // Retain count 3 
    myString = nil;    // Retain count 2 
    NSLog(@"C: %@", weakString); // Retain count 3 

    NSAssert(weakString != nil, @"weakString is kept alive by the autorelease pool"); 
} 

// retain count 0 
NSAssert(weakString == nil, @"Autorelease pool has drained."); 

Perché NSLog inserisce la stringa in un pool di autorelease? Questo è un dettaglio di implementazione.

È possibile utilizzare il debugger o gli strumenti per seguire il conteggio di mantenimento dell'istanza NSString. I conteggi di ritenzione esatti non sono importanti, ma fa luce su ciò che accade dietro le quinte. L'importante è che l'istanza NSString sia deallocata quando il pool di autorelease viene scaricato.

+1

Sì, questo ha praticamente spiegato, stavo pensando che NSlog() aumenterà il conteggio dei suoi parametri, ma la tua risposta è molto più ragionevole. Grazie mille Darren. –

0

Penso che siano solo alcuni dettagli di implementazione. La variabile debole viene cancellata, ma non immediatamente. Ad esempio, funziona come previsto:

NSString *myString = [[NSString alloc] initWithFormat:@"John"]; 
NSString * __weak weakString = myString; 
@autoreleasepool { 
    NSLog(@"Before: %@", weakString); 
    myString = nil; 
} 
NSLog(@"After: %@", weakString); // nil