2012-03-13 9 views
21

ACTUALIZACIÓN: ¡Este problema se ha corregido a partir de Xcode 4.6!strong @property con __attribute __ ((NSObject)) para un tipo CF no retiene

Esta técnica ahora funciona como estaba previsto de nuevo. Sin embargo, asegúrese de leer las notas en la parte superior de la excelente respuesta de Rob Napier antes de usarlo en su código.

Post original

(ARC, Xcode 4.3.1, iOS 5.1)

que tienen una fuerte propiedad de un tipo CF (CGImage) que yo quiero ser manejados automáticamente por arco utilizando __attribute__((NSObject)) (como si se hubiera conservado la liberación & en el setter sintetizado, y no se trata en dealloc), pero no funciona: el objeto no se conserva cuando asigno la propiedad.

Un ejemplo mínimos para reproducir:

@interface TestClass : NSObject 
@property (nonatomic, strong) __attribute__((NSObject)) CFStringRef str; 
@end 

// ...In some function 
CFStringRef str = (__bridge CFStringRef)[NSString stringWithFormat:@"%g", 2.5]; 
NSLog(@"%ld", CFGetRetainCount(str)); 
TestClass *obj = [[TestClass alloc] init]; 
obj.str = str; 
NSLog(@"%ld", CFGetRetainCount(str)); 

que imprime '1' dos veces.

Ahora lo extraño es que (aunque no estoy seguro de esto) Creo que funcionó correctamente antes he actualizado a iOS 5.1 & Xcode 4.3.1 (de iOS 5 & Xcode 4.2), y con él pasó de gdb a lldb. ¿Puede alguien que no se haya actualizado (o sepa cómo cambiar el compilador) quizás confirme?

+0

Una solución sería simplemente usar una propiedad 'NSString *', y usar un molde '__bridge' al asignar. – jtbandes

+0

ahora no recibo nada de [este enlace] (http://clang.llvm.org/docs/AutomaticReferenceCounting.html#objects.operands.casts) espera que llegue algo –

+0

Bueno, lamentablemente esto es sólo un ejemplo para reproducir, en mi código real que estoy usando tengo un CGImage. Editaré la publicación. –

Respuesta

33

Edit2 (mar 2013) FYI para aquellos interesados ​​en esta técnica, ARC documentation for clang incluye la siguiente nota:

No se recomienda el uso de __attribute__((NSObject)) typedefs. Si es absolutamente necesario usar este atributo, sea muy explícito sobre el uso de typedef, y no suponga que será preservado por características de lenguaje como __typeof y sustitución de argumento de plantilla de C++.

Fundamento

Cualquier operación compilador que por cierto bandas Tipo “azúcar” de un tipo producirá un tipo sin el atributo, que puede resultar en un comportamiento inesperado.


EDITAR La continuación es interesante, pero probablemente irrelevante. Este es un error y deberías abrir un radar. Como señaló @lnafziger, esto es legal y se supone que debe cumplirse. El error es que no se respeta cuando se incluye nonatomic. Si elimina nonatomic, entonces funciona. Nada en la definición nonatomic sugiere que esto sea por diseño.


Esto es algo inteligente, pero creo que veo por qué no funciona. Puede confirmar, por cierto, que no está funcionando al generar el ensamblador y observar que setStr: no llama al objc_storeStrong(). Hace una asignación simple.

El problema es que su definición de la propiedad no se ajusta a la definición de un puntero de objeto puede retener (énfasis añadido):

Un puntero puede retener objeto (o el puntero puede retener) es un valor de un objeto puede retener tipo de puntero (tipo retenible). Hay tres tipos de tipos de puntero objeto retainable:

  • punteros de bloques (formados mediante la aplicación de la intercalación (^) sigil declarador a un tipo función)
  • punteros de objeto Objetivo-C (ID, Clase, NSFoo *, etc.)
  • typedefs marcados con __attribute __ ((NSObject))

¿Ha creado un typedef como se especifica? No, no lo hiciste. OK, entonces, ¿cómo haríamos esto?

typedef __attribute__((NSObject)) CFStringRef MYStringRef; 

@interface TestClass : NSObject 
@property (nonatomic, strong) MYStringRef str; 
@end 

... the rest of your code ... 

Esto imprimirá "1" y luego "2" como supongo que espera. Me asusta por razones no especificadas, pero mirando la salida del ensamblador, todo parece estar bien y no puedo pensar en ningún problema específico o violación aquí.

Puede justificarse la apertura de un radar para esto. El hecho de que un typedef no se trate de la misma manera que un tipo especificado es sorprendente al menos, incluso si está documentado.

EDIT: comentario Observando @ de lnafziger del ObjC Programming Language, no hay duda, ya sea un error en la especificación ARC/aplicación o un error en el documento vinculado, por lo que uno de ellos debe ser fijo.

+5

Abrió un radar. Bueno, fue capaz de encontrar las condiciones en las que funciona por cierto. –

+0

+1 ¡excelente respuesta! – lnafziger

+2

Si abrió un radar, publique el # aquí. – bbum

Cuestiones relacionadas