weakreference unowned objective-c weak-references reference-counting strong-references

objective c - unowned - ¿Por qué no se borra mi referencia débil justo después de que desaparezcan los fuertes?



weakreference c# (4)

Cuando tu lo hagas

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

strongPtr está apuntando a un nuevo objeto asignado, y como el objeto anterior al que apuntaba también no fue desasignado, el puntero débil aún apunta a una dirección válida.

por cierto. puede imprimir la dirección de memoria de un objeto con

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

Soy un poco obstinado, pero quiero entender bien las referencias débiles y fuertes, por eso te lo pido una vez más.

Considera esto:

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

El resultado es myText: (null) y es bastante obvio: la referencia débil se establece en nulo justo después de la asignación, porque no hay una referencia fuerte al objeto apuntado.

Pero en este 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);

La salida:

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 // <== ??

Mi pregunta:

¿Por qué después de strongPtr = [[NSString alloc] initWithString:@"abc"]; el valor débil del puntero no cambia a nil (¿por qué el objeto creado al principio todavía existe en la memoria, a pesar de que no tiene ningún refs fuerte? - ¿o tal vez sí?)

He intentado con eso: (pero no es bueno para agregar un comentario, supongo). He incluido el código donde estoy creando un strongPtr en @autorealesepool. No estoy seguro si es la solución correcta, pero funciona ...

__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);

Salida:

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)


Del código ensamblador se puede ver que acceder a weakPtr genera una llamada objc_loadWeak .

De acuerdo con la documentación de Clang , objc_loadWeak retiene y autorrealiza el objeto y es equivalente a

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

Esto (con suerte) explica por qué ambos

if(strongPtr == weakPtr) ...

y

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

crear referencias autorreleases adicionales.

Este no es un problema especial de NSString , podría reproducir el mismo comportamiento con una clase personalizada (simple).


No estoy seguro de que la pregunta de OP y / o la respuesta aceptada aquí sigan siendo válidas, al menos no a partir de los resultados que estoy viendo con iOS9 / Xcode7.

Aquí hay una versión (ligeramente limpiada) del código del OP ...

#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; }

Y aquí está la salida (truncada) ...

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

Aquí el acceso a las referencias débiles en los condicionales (según la explicación de la respuesta aceptada) no mantiene una referencia de liberación automática como puede ver por (nulo) en la salida.

... ¿O cambié accidentalmente la pregunta del OP hasta el punto en que oculté lo que estaba viendo? ¿O quizás es porque ahora ARC está activado por defecto?


Primero, no experimente con referencias débiles u otro comportamiento de administración de memoria en NSString , hay demasiada magia en esa clase. No es que las referencias débiles no funcionen con NSString , solo que el comportamiento es un poco más complicado de lo que cabría esperar y conduce fácilmente a conclusiones incorrectas. Vea estas preguntas anteriores:

Cuando envuelve su ejemplo de código con un grupo de liberación automática y registra el puntero de cadena débil después, es nil . Incluso podría darse el caso de que tuvieras un comportamiento similar con otras clases distintas de NSString : simplemente no tienes la garantía de que las referencias débiles se eliminarán en el momento preciso en que pierdes la última referencia fuerte a un objeto. O tal vez lo sea, pero es difícil saber cuándo desaparece exactamente la última referencia fuerte debido a los grupos de autorreleases en juego, como se insinúa en este ejemplo (y muy bien explicado por la respuesta de Martin).