¿Variables de instancia de Objective-C?
Estoy seguro de que mi confusión aquí es solo el resultado de estar atrapado en una "mentalidad Java" y no entender en qué se diferencia Obj-C en este caso.
En Java, puedo declarar una variable en una clase, como esta, y cada instancia de esa clase tendrá la suya propia:
MyClass {
String myVar;
MyClass() {
// constructor
}
}
En Obj-C intenté hacer lo mismo declarando una variable solo en el archivo .m así:
#import "MyClass.h"
@implementation MyClass
NSString *testVar;
@end
Mi expectativa aquí era que esta variable tuviera un alcance limitado a esta clase. Entonces creé una segunda clase (idéntica):
#import "MySecondClass.h"
@implementation MySecondClass
NSString *testVar;
@end
Lo que estoy viendo (y me tiene desconcertado) es que cambiar la variable en una clase afecta el valor visto en la otra clase. De hecho, si establezco un punto de interrupción y luego "Salto a la definición" de la variable, me lleva al
He creado un proyecto Xcode extremadamente pequeño que demuestra el problema aquí .
Cambia esto:
@implementation MyClass
NSString *testVar;
@end
a:
@implementation MyClass {
NSString *testVar;
}
// methods go here
@end
y obtendrás lo que esperabas.
Tal como lo tenías, en realidad estás creando una variable global. El vinculador combinó las dos variables globales en una, por lo que ambas cambiaron cuando configuró una. La variable entre llaves será una variable de instancia adecuada (y privada).
Editar: Después de recibir un voto negativo sin razón aparente, pensé en señalar la forma "antigua" de hacer las cosas y la nueva.
A la antigua usanza:
algunaclase.h
@interface SomeClass : UIViewController <UITextFieldDelegate> {
UITextField *_textField;
BOOL _someBool;
}
@property (nonatomic, assign) BOOL someBool;
// a few method declarations
@end
algunaclase.m
@implementation SomeClass
@synthesize someBool = _someBool;
// the method implementations
@end
Ahora la forma nueva y mejorada con el compilador moderno Objective-C:
algunaclase.h
@interface SomeClass : UIViewController
@property (nonatomic, assign) BOOL someBool;
// a few method declarations
@end
algunaclase.m
@interface SomeClass () <UITextFieldDelegate>
@end
@implementation SomeClass {
UITextField *_textField;
}
// the method implementations
@end
La nueva forma tiene varias ventajas. La principal ventaja es que ninguno de los detalles específicos de la implementación sobre la clase aparece en el archivo .h. Un cliente no necesita saber qué delega las necesidades de implementación. El cliente no necesita saber qué ivars uso. Ahora, si la implementación necesita un nuevo ivar o necesita usar un nuevo protocolo, el archivo .h no cambia. Esto significa que se vuelve a compilar menos código. Es más limpio y mucho más eficiente. También facilita la edición. Cuando estoy editando el archivo .m y me doy cuenta de que necesito un nuevo ivar, hago el cambio en el mismo archivo .m que ya estoy editando. No es necesario cambiar de un lado a otro.
También tenga en cuenta que la implementación ya no necesita un ivar o @synthesize
para la propiedad.