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:
- Attritube débil no funciona como se esperaba
- ¿Por qué las propiedades débiles de NSString no se lanzan en iOS?
- NSString retiene el recuento
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).