2010-05-06 148 views
13

Actualización: muchas personas insisten en que necesito declarar un iVar para la propiedad. Algunos dicen que no, porque estoy usando Modern Runtime (64 bit). Puedo confirmar que he estado usando @property sin iVars con éxito desde hace meses. Por lo tanto, creo que la respuesta 'correcta' es una explicación de por qué en 64 bits de repente tengo que declarar explícitamente el iVar cuando (y solo cuando) voy a acceder a él desde una clase infantil. El único que he visto hasta ahora es un posible error de GCC (gracias Yuji). No es tan simple después de todo ... Para aclarar el posible error es este: Al heredar de una clase base, un niño no puede acceder a la iVar IF del padre que ese mismo niño implementa un acceso no definido usando @synthesize ANTES de que se acceda al iVar.(No tan) Problema de herencia tonto de Objective-C al usar la propiedad - ¿Error de GCC?

He estado rascándome la cabeza con esto por un par de horas - No he usado mucho la herencia.

Aquí he configurado una clase simple Test B que hereda de la Prueba A, donde se declara un ivar. Pero obtengo el error de compilación de que la variable no está declarada. Esto solo ocurre cuando agrego la propiedad y sintetizo las declaraciones, funciona bien sin ellas.

Testa Header:

#import <Cocoa/Cocoa.h> 
@interface TestA : NSObject { 
    NSString *testString; 
} 
@end 

Testa Implementación está vacía:

#import "TestA.h" 
@implementation TestA 
@end 

TestB Header:

#import <Cocoa/Cocoa.h> 
#import "TestA.h" 
@interface TestB : TestA { 
} 
@property (nonatomic, retain) NSString *testProp; 
@end 

TestB Aplicación (Error - 'testString' es no declarado)

#import "TestB.h" 
@implementation TestB 
@synthesize testProp; 
- (void)testing{ 
    NSLog(@"test ivar is %@", testString); 
} 
@end 
+0

Si "solo ocurre cuando [usted] agrega la propiedad y sintetiza las declaraciones", no son una arenga roja. Como mencioné, en realidad están causando el problema porque no hay una variable de instancia de cadena 'testProp'. Declaré uno y el problema desapareció. –

+0

Acabo de verificar para asegurarme de que no estaba yendo mentalmente, y uso @property sin un ivar todo el tiempo sin ningún problema. Estoy de acuerdo en que declarar una 'ivar' la soluciona ', pero realmente no explica por qué solo no se puede compilar cuando utilizo la herencia. Solo para volver a iterar, no estoy declarando ivars para aproximadamente 50 propiedades solo dentro del mismo proyecto, en muchas clases diferentes, todas sin problema. –

Respuesta

10

Creo que este es el error de GCC 4.2.1. hice el archivo con el contenido foo.m

#import <Foundation/Foundation.h> 
@interface TestA : NSObject { 
    NSString *testString; 
} 
@end 

@implementation TestA 
@end 

@interface TestB : TestA { 
} 
@property (retain) NSString *testProp; 
@end 

@implementation TestB 
@synthesize testProp; 
- (void)testing{ 
NSLog(@"test ivar is %@", testString); 
} 
@end 

nota que está bien en el modo de 64 bits para omitir la variable de instancia. Mi GCC 4.2.1 en OS X 10.6.3 me dio un error:

$ gcc -arch x86_64 -c foo.m 
aho.m: In function ‘-[TestB testing]’: 
aho.m:19: error: ‘testString’ undeclared (first use in this function) 
aho.m:19: error: (Each undeclared identifier is reported only once 
aho.m:19: error: for each function it appears in.) 

Este compilado sin problema cambiando

NSLog(@"test ivar is %@", testString); 

a

NSLog(@"test ivar is %@", self->testString); 

Clang compila sin ningún problema.

(En el modo de 32 bits, lo tengo

$ gcc -arch i386 -c foo.m 
aho.m:17: error: synthesized property ‘testProp’ must either be named 
the same as a compatible ivar or must explicitly name an ivar 
aho.m: In function ‘-[TestB testing]’: 
aho.m:19: error: ‘testString’ undeclared (first use in this function) 
aho.m:19: error: (Each undeclared identifier is reported only once 
aho.m:19: error: for each function it appears in.) 

que es un comportamiento perfectamente lo esperado, como escribió Manjunath.)

Sin embargo Creo que es generalmente un lugar mala idea para acceder a una variable de instancia de la superclase: cuando implementa los métodos la superclase, no puede asumir nada sobre la variable de instancia porque la subclase podría ajustarla de la peor manera posible. Al menos debe escribir qué tipo de operación en la variable de instancia está permitida o no ...Recuerde que es posible que necesite mantener su código durante años. Preferiría mantener contratos de programación entre varias partes del código en el nivel de métodos y propiedades.

Por ultimo, debe cambiar

@property NSString *testProp; 

a

@property (copy) NSString *testProp; 

o al menos a

@property (retain) NSString *testProp; 

si no estás usando GC en OS X. De lo contrario EXP_BAD_ACCESS estará esperando !

+0

La primera parte es incorrecta; pero para la segunda parte: a menos que usted/necesite/para soportar el acceso con hebras, (lo que sea, no atómico) también se sugiere. –

+1

Naaaah! ¿Los dos realmente compilaron el archivo? Combiné todo en un archivo '.m' y gcc dio el error. Edito la publicación anterior para incluir el archivo que utilicé. – Yuji

+0

Manjunath - ¿Ya estoy importando la clase base? Vea el código de arriba. –

1

creo que sólo hay un error tipográfico - debe ser "testString" no "prueba"

+0

Gracias - se han actualizado. Desafortunadamente no fue el problema, pero sí me ayudó a reducirlo. –

1

Estoy viendo error: 'testString' undeclared (first use in this function) cuando el @synthesize está justo antes del método testing. El error desaparece si muevo el @synthesize debajo de la implementación del método. Esto podría deberse a que la clase TestB no tiene una variable de instancia de cadena testProp para usar con la propiedad declarada. (En el tiempo de ejecución Legacy (32 bits), debe declarar variables de instancia para usar para las propiedades: en el tiempo de ejecución moderno (Mac de 64 bits, iPhone) se pueden inferir, por lo que declararlos es opcional.) ¿Es posible que En su lugar, ¿quiso nombrar la propiedad testString?


EDIT: En GCC 4.2, funciona si cambia TestB.h a lo siguiente:

#import "TestA.h" 

@interface TestB : TestA { 
    NSString *testProp; // <-- Adding this fixes the errors 
} 
@property NSString *testProp; 

@end 

Sin embargo, usando el compilador Clang-LLVM, el código funciona sin modificar. Tal vez este es un error para archivar.

+0

Sí, eso fue un error de copiar y pegar, corregido. Pero he estado usando propiedades durante 6 meses sin declarar ivars?!? p.ej. @property (no atómico, retener) –

+0

¿O lo retendrá? De cualquier manera, no lo resuelve por desgracia. –

+0

No tiene que declarar variables de instancia para las propiedades si está utilizando el tiempo de ejecución moderno. El tiempo de ejecución moderno incluye iPhone OS y 64 bits en OS X. – Yuji

1

Acabo de toparme con el mismo problema pero las fuentes eran lo suficientemente complejas como para no entender lo que hacía que iVar del padre fuera inaccesible cuando usaba GCC. Solo sabía con certeza que hace unos meses y antes los cambios en mi código funcionaron y también que está funcionando con clang, que he estado usando por un tiempo. De repente tuve que construir con GCC y ya no lo haría.

Al menos este artículo me dio un bypass (declare iVars). Me sorprende que la última versión de XCode no incluya un compilador fijo

Cuestiones relacionadas