2012-02-08 20 views
5

Si tengo un trozo de código que se parece a esto:duración de las variables locales débiles con ARC

- (void)testSomething 
{ 
    __weak NSString *str = [[NSString alloc] initWithFormat:@"%@", [NSDate date]]; 
    NSLog(@"%@", str); 
} 

la salida será (nulo) ya que no existen fuertes referencias a str y se dará a conocer de inmediato después de asignarlo. Esto tiene sentido y se explica en la guía Transición a ARC.

Si mi código es el siguiente:

- (void)testSomething 
{ 
    __weak NSString *str = [NSString stringWithFormat:@"%@", [NSDate date]]; 
    NSLog(@"%@", str); 
} 

luego imprime correctamente a la fecha actual. Obviamente, esperaría que funcionara en un mundo que no sea ARC, ya que str se lanzaría automáticamente y, por lo tanto, sería válido hasta que este método finalice. Sin embargo, en el código habilitado para ARC, las personas generalmente consideran que los dos formularios (stringWithFormat & alloc/initWithFormat) son equivalentes.

Así que mi pregunta es si el código como el segundo ejemplo está garantizado para trabajar bajo ARC. Es decir, si tengo una referencia débil a un objeto que obtengo a través de lo que normalmente consideraríamos un constructor de conveniencia de autorrelleno, ¿está seguro de para usar esa referencia en el mismo alcance que normalmente tendría sin ARC (es decir, hasta que el método sale)?

+1

Pregunta interesante, pero sospecho que la mejor respuesta es "no deberías preocuparte". –

+0

Probablemente tengas razón. Esta pregunta es realmente solo para asegurarme de que entiendo las respuestas a algunas otras preguntas que he visto. – UIAdam

+0

UIAdam, estoy con Kevin en este caso. Deje que el compilador se preocupe por la asignación de memoria. '__weak' es un método algo ineficaz para controlar el tiempo de vida de las instancias. Si desea controlar explícitamente la duración del artículo, utilice el formulario '+ alloc' asignado a una referencia fuerte. Entonces nula esa referencia al salir. Sin mencionar una referencia es el nuevo '-release'. IMO, '__weak' se usa para romper los ciclos de retención, nada más. Andrew P.S. Con ARC, todos deberíamos "recostarnos y pensar en Inglaterra". – adonoho

Respuesta

5

Las convenciones de autorrelleno y asignación siguen aplicando en el mundo de ARC. La única diferencia es que ARC insertará llamadas de retención/liberación adicionales para que sea mucho más difícil filtrar objetos o acceder a un objeto desasignado.

En este código:

__weak NSString *str = [[NSString alloc] initWithFormat:@"%@", [NSDate date]]; 

El único lugar se retiene el objeto (o equivalente) es la alloc. ARC insertará automáticamente un comando de liberación, haciendo que se desasigne inmediatamente.

Mientras tanto, en este código:

__weak NSString *str = [NSString stringWithFormat:@"%@", [NSDate date]]; 

Por convención, el valor de retorno de un constructor de conveniencia como esto debe ser un objeto autoreleased *. Eso significa que el grupo de liberación automática actual ha retenido el objeto y no lo liberará hasta que se drene el conjunto. Por lo tanto, está seguro de que este objeto existirá durante al menos la duración de su método, aunque probablemente no deba confiar en este comportamiento.

(* o retenido de alguna otra manera)

+1

Sin embargo, tenga en cuenta que si tiene 'NSString * str = [NSString stringWithFormat: @"% @ ", [NSDate date]]; __weak NSString * weakStr = str; 'y si' str' ya no se referencia después de la asignación a 'weakStr' (y por lo tanto está fuera del alcance), entonces' weakStr' * puede * terminar en cero, dependiendo de si '+ stringWithFormat : 'en sí mismo fue compilado bajo ARC. –

+0

En ARC, no se garantiza que el valor de retorno de un constructor de conveniencia termine en el grupo de liberación automática. Ver mi respuesta para más detalles y un ejemplo. –

1

La vida útil de una variable débil local no está garantizado en absoluto. Si el objeto al que apunta la variable se desasigna, la variable débil apuntará a nil después.

Si tiene una referencia débil a un objeto que obtuvo a través de un método que no devuelve un objeto retenido, es no seguro para suponer que este objeto vive hasta que el método finalice. Si quiere asegurarse de que el objeto sobrevive, use una referencia fuerte.

Aquí es un ejemplo que muestra que el valor de retorno de un método no retención no está garantizada para terminar en la piscina autorelease:

  • Crear un nuevo proyecto IOS (Single Ver App utilizando ARC y guiones gráficos)
  • Añadir este método para la AppDelegate.m:

    + (id)anObject 
    { 
        return [[NSObject alloc] init]; 
    } 
    
  • Reemplazar -application:didFinishLaunchingWithOptions::

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
    { 
        __weak id x = [AppDelegate anObject]; 
        NSLog(@"%@", x); 
        return YES; 
    } 
    
  • Importante: Ahora ajustar el nivel de optimización para la depuración de -Os.

En este ejemplo, +[AppDelegate anObject] actúa como un constructor de conveniencia, pero verá (null) registra si se ejecuta en un dispositivo con -Os optimización. El motivo es una ingeniosa optimización de ARC que evita la sobrecarga de agregar el objeto al grupo de autorrelease.

Puede haber notado que cambié a no usar un método de biblioteca como +[NSString stringWithFormat:]. Estos parecen poner siempre objetos en el grupo de autorrelease, que puede ser por razones de compatibilidad.

+0

Por supuesto, el objeto no va a terminar automáticamente en un grupo de autorrelease sin que se haya invocado automáticamente sobre él. Ese nunca ha sido el caso. Pero en el código real donde tiene un constructor de conveniencia que quiere/necesita ser consistente con las convenciones existentes (es decir, que el objeto devuelto se libera automáticamente), entonces llamaría a liberación automática y por lo tanto se comportaría como un objeto liberado independientemente de si estás usando ARC o no. – UIAdam

+0

En realidad, para el método '-anObject' anterior, ARC inserta automáticamente una llamada a' objc_autoreleaseReturnValue' o 'objc_returnAutoreleaseReturnValue'. El objeto terminará en el grupo de liberación automática si se llama a '-anObject' desde un código que no sea ARC, o incluso en ARC a menos que establezca el nivel de optimización -Os. –

+0

Y desde ARC, la convención no es agregar el objeto al grupo de autorrelease, pero se intenta optimizar para que no sea necesario agregar al grupo de autorrelease. Agregar al grupo de autorrelease se describe como "el peor caso". Consulte http://clang.llvm.org/docs/AutomaticReferenceCounting.html#objects.operands.other-returns.Por lo tanto, su segundo ejemplo no está garantizado por ARC; puede funcionar ahora, pero no está garantizado. –

Cuestiones relacionadas