28

Sono un po 'testardo, ma voglio capire bene i riferimenti deboli e forti, ecco perché ti sto chiedendo ancora una volta.Perché il mio riferimento debole non viene cancellato subito dopo che quelli forti sono spariti?

considerare questo:

__weak NSString* mySecondPointer = myText; 
NSLog(@"myText: %@", myText); 

Il risultato è myText: (null) ed è abbastanza evidente - riferimento debole è impostata su null solo dopo l'assegnazione, causa non c'è una forte riferimento all'oggetto appuntito.

Ma in questo caso:

__strong NSString* strongPtr = [[NSString alloc] initWithFormat:@"mYTeSTteXt %d"]; 
// weak pointer points to the same object as strongPtr 
__weak NSString* weakPtr = strongPtr; 
if(strongPtr == weakPtr) 
    NSLog(@"They are pointing to the same obj");   
NSLog(@"StrongPtr: %@", strongPtr); 
NSLog(@"weakPtr: %@", weakPtr); 

NSLog(@"Setting myText to different obj or nil"); 

// after line below, there is no strong referecene to the created object: 
strongPtr = [[NSString alloc] initWithString:@"abc"]; // or myText=nil; 

if(strongPtr == weakPtr) 
    NSLog(@"Are the same"); 
else 
    NSLog(@"Are NOT the same"); 
NSLog(@"StrongPtr: %@", strongPtr); 
// Why weak pointer does not point to nul 
NSLog(@"weakPtr: %@", weakPtr); 

L'output:

2013-03-07 09:20:24.141 XMLTest[20048:207] They are pointing to the same obj 
2013-03-07 09:20:24.142 XMLTest[20048:207] StrongPtr: mYTeSTteXt 3 
2013-03-07 09:20:24.142 XMLTest[20048:207] weakPtr: mYTeSTteXt 3 
2013-03-07 09:20:24.143 XMLTest[20048:207] Setting myText to different obj or nil 
2013-03-07 09:20:24.143 XMLTest[20048:207] Are NOT the same 
2013-03-07 09:20:24.144 XMLTest[20048:207] StrongPtr: abc 
2013-03-07 09:20:24.144 XMLTest[20048:207] weakPtr: mYTeSTteXt 3 // <== ?? 

La mia domanda:

Perché dopo strongPtr = [[NSString alloc] initWithString:@"abc"]; debole valore del puntatore non viene modificato a zero (perché l'oggetto creato all'inizio esiste ancora nella memoria, nonostante non abbia alcun riferimento forte? ? - o forse ha)


ho provato che uno: (ma non è bene per l'aggiunta di un commento suppongo). Ho incluso il codice in cui sto creando un strongPtr in @autorealesepool. Io non so se è corretta soluzione, ma funziona ...

__strong NSString* strongPtr; 
    __weak NSString* weakPtr; 
    @autoreleasepool { 


     strongPtr = [[NSString alloc] initWithFormat:@"mYTeSTteXt %d", 3]; 

     // weak pointer point to object create above (there is still strong ref to this obj) 
     weakPtr = strongPtr; 
     if(strongPtr == weakPtr) NSLog(@"They are pointing to the same obj");   

     NSLog(@"StrongPtr: %@", strongPtr); 
     NSLog(@"weakPtr: %@", weakPtr); 

     NSLog(@"Setting myText to different obj or nil"); 

    // after line below, there is no strong referecene to the created object: 
    strongPtr = [[NSString alloc] initWithString:@"abc"]; 


    } 

    if(strongPtr == weakPtr) 
     NSLog(@"Are the same"); 
    else 
     NSLog(@"Are NOT the same"); 
    NSLog(@"StrongPtr: %@", strongPtr); 
    // Why weak pointer does not point to nul 
    NSLog(@"weakPtr: %@", weakPtr); 

uscita:

2013-03-07 09:58:14.601 XMLTest[20237:207] They are pointing to the same obj 
2013-03-07 09:58:14.605 XMLTest[20237:207] StrongPtr: mYTeSTteXt 3 
2013-03-07 09:58:14.605 XMLTest[20237:207] weakPtr: mYTeSTteXt 3 
2013-03-07 09:58:14.606 XMLTest[20237:207] Setting myText to different obj or nil 
2013-03-07 09:58:14.607 XMLTest[20237:207] Are NOT the same 
2013-03-07 09:58:14.607 XMLTest[20237:207] StrongPtr: abc 
2013-03-07 09:58:14.608 XMLTest[20237:207] weakPtr: (null) 
+4

+1 Ottimo esempio di una domanda! –

+5

@FruityGeek, potresti spiegare il problema invece di lasciar perdere le osservazioni intelligenti? – zoul

+0

@FruityGeek: altri suggerimenti? –

risposta

17

Dal codice di assembly si può vedere che l'accesso a weakPtr genera una chiamata objc_loadWeak.

Secondo il Clang documentation, objc_loadWeak conserva e autoreleases l'oggetto ed è equivalente a

id objc_loadWeak(id *object) { 
    return objc_autorelease(objc_loadWeakRetained(object)); 
} 

questo (si spera) spiega perché sia ​​

if(strongPtr == weakPtr) ... 

e

NSLog(@"weakPtr: %@", weakPtr); 

creare ulteriore riferimenti autoreleased.

Questo non è un problema speciale NSString, potrei riprodurre lo stesso comportamento con una classe personalizzata (semplice).

+1

Sembra una cosa un po 'avanzata, ma ragionevole;) Grazie. –

+1

Bella cattura! Stavo strizzando gli occhi per il montaggio per un po ', ma non sono arrivato a cercare la chiamata 'objc_loadWeak'. Ciò significa in realtà che ogni accesso di riferimento debole passa attraverso due chiamate di gestione della memoria aggiuntive? – zoul

+1

@zoul: Grazie! - Sì, sembra così, anche nel codice ottimizzato (rilascio) ho trovato le chiamate. Il motivo * potrebbe essere * per evitare che il riferimento debole venga cancellato mentre si accede in un ambiente multithreading, ma questo è puro indovinello. - Btw. L'ho capito usando una classe non ARC personalizzata che sovrascrive retain/release/autorelease. (Non avrei mai ammettere che ho controllato il retainCount nel debugger prima, perché questo provoca downvotes immediati :-) –

1

quando fate

strongPtr = [[NSString alloc] initWithString: @ "abc"]

you strongPtr è poin il nuovo puntatore al nuovo oggetto assegnato e poiché l'oggetto precedente a cui puntava non veniva deallocato, il puntatore debole punta ancora a un indirizzo valido.

btw. è possibile stampare l'indirizzo di memoria da un oggetto con

NSLog (@ "% @", [NSString stringWithFormat: @ "% p", theObject])

+0

Sì, ma se scrivo strongPtr = nil, il risultato è lo stesso. –

+0

Supponendo ARC, l'istanza precedente non può essere trapelata e dovrebbe essere deallocata. Infine. – zoul

+0

strongPtr = nil non equivale a inviare dealloc a un oggetto. – peko

3

In primo luogo, non sperimentare riferimenti deboli o altri comportamenti di gestione della memoria su NSString, c'è troppa magia in quella classe. Non che i riferimenti deboli non funzionino con NSString, solo il comportamento è leggermente più complicato di quanto ci si aspetterebbe e porta facilmente a conclusioni errate.Vedere queste domande precedenti:

Quando si avvolge il tuo esempio di codice con una piscina autorelease e accedere il puntatore stringa di debolezza in seguito, è nil davvero. Potrebbe anche accadere che si ottenga un comportamento simile con classi diverse da NSString - semplicemente non si garantisce che i riferimenti deboli vengano cancellati nel preciso momento in cui si perde l'ultimo riferimento forte a un oggetto. O forse lo sei, ma è difficile dire quando esattamente l'ultimo riferimento forte scompare a causa dei pool di autorelease in gioco, come suggerito da questo esempio (e ben spiegato dalla risposta di Martin).

+0

Sì, grazie per questo ... penso che si può contrassegnare il mio post più possibile duplicare (non ho abbastanza reputazione) di http://stackoverflow.com/questions/14116993/objective-c-weak-attritube-dont-work-as-expected –

+0

Questo non è un numero speciale di 'NSString'. Ho riprodotto lo stesso comportamento con una classe personalizzata. Accedere al puntatore debole crea riferimenti autoreleased, vedere la mia risposta. –

+0

@guitar_freak: È bello mantenere questa domanda, poiché la risposta di Martin spiega precisamente il comportamento. Puoi contrassegnarlo come accettato? – zoul

1

Non sono sicuro che la domanda dell'OP e/o la risposta accettata qui sia ancora valida, almeno non dei risultati che sto vedendo con iOS9/Xcode7.

Ecco una versione (leggermente ripulito) del codice del PO ...

#import <Foundation/Foundation.h> 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool 
    { 
     NSString* __strong strongPtr = [[NSString alloc] initWithFormat:@"Life, Universe, Everything: %d", 42]; 
     NSString* __weak weakPtr = strongPtr; 

     NSLog(strongPtr == weakPtr ? @"Same" : @"Different"); 
     NSLog(@" StrongPtr: %@", strongPtr); 
     NSLog(@" weakPtr: %@", weakPtr); 

     NSLog(@"Changing strongPtr to something else..."); 
     // After this is set, there is no strong reference to the created object 
     strongPtr = [[NSString alloc] initWithFormat:@"Drink: %@", @"Pan-galactic Gargle Blaster!"]; 

     NSLog(strongPtr == weakPtr ? @"Same" : @"Different"); 
     NSLog(@" StrongPtr: %@", strongPtr); 
     NSLog(@" weakPtr: %@", weakPtr); 
    } 

    return 0; 
} 

Ed ecco il (troncato) in uscita ...

Same 
    StrongPtr: Life, Universe, Everything: 42 
    weakPtr: Life, Universe, Everything: 42 

Changing strongPtr to something else... 

Different 
    StrongPtr: Drink: Pan-galactic Gargle Blaster! 
    weakPtr: (null) 

Program ended with exit code: 0 

Qui l'accesso ai riferimenti deboli nel i condizionali (secondo la spiegazione della risposta accettata) non mantengono un riferimento rilasciato automaticamente come si vede dal (nulla) nell'output.

... o ho accidentalmente cambiato la domanda dell'OP al punto in cui ho nascosto quello che sta vedendo? O forse perché ora ARC è attivo di default?

Problemi correlati