Pregunta

¿Cuál es la sintaxis adecuada para acceder a una variable de instancia en Objective-C?

Suponga que tenemos esta variable:

@interface thisInterface : UIViewController {
    NSMutableString *aString;
}

@property (nonatomic, retain) NSMutableString *aString;

y que está sintetizado.

Cuando queremos acceder a él, primero nos gustaría asignarlo e inicializarlo. Habiendo programado en Objective-C durante aproximadamente un mes, he visto dos formas diferentes de sintaxis. He visto a la gente hacer simplemente aString = [[NSMutableString alloc] initWithString:@"hi"], donde asignan la cadena así; También he visto a la gente comenzar con self.aString y luego proceden a inicializar su ivar. Supongo que solo estoy tratando de averiguar cuál es la forma más adecuada de inicializar una variable de instancia, porque con el ejemplo anterior, he recibido errores exc_bad_access. Después de preparar el self. Sin embargo, no apareció.

Perdóname si esta es una pregunta duplicada, pero después de leer algunas publicaciones en So, me dio curiosidad. Estoy tratando de aprender la sintaxis adecuada con Objective-C porque prefiero ser apropiado en lugar de descuidado.

¿Fue útil?

Solución

Si ha declarado una propiedad y @synthesize En el archivo .m, simplemente estés así:

self.aString = @"hi"; // or [[NSMutableString alloc] initWithString:@"hi"];

Usando self.varName Aprovecha lo que realmente hace su declaración de propiedad: maneja la retención del nuevo valor (ya que su propiedad tiene el retain atributo), liberando el valor anterior, etc. para usted.

Si solo lo haces:

aString = someValue;

... puede estar filtrando el valor original que estaba en aString, ya que sin usar self.aString Está accediendo a la variable directamente frente a la propiedad.

Otros consejos

Tenga en cuenta la diferencia entre self->varName y self.varName

El primero es puntero acceso. El segundo es propiedad acceso.

¿Por qué es eso importante? El acceso al puntero es directo. El acceso a la propiedad, por otro lado, utiliza getters y setters (ya sean @synthesized O no). Además, como conveniencia, los accesorios @synthesizados se encargan de la gestión de la memoria por usted (es decir, cuando se usa self.varName = ...;), mientras varName = ...; solo hace lo que dice, es decir, la tarea -> (hay la explicación de los errores exc_bad_access que podría estar recibiendo).

Sintácticamente, ambas formas son correctas. Si desea comunicar mejor la intención, use self->varName Cuando desea trabajar directamente con el puntero y usar self.varName Cuando quieras aprovechar el @property conveniencia.

Estas son todas las combinaciones posibles (creo) que son bien y los malos solo son correctos cuando aString propiedad tiene retain atributo:

@property (nonatomic, retain) NSMutableString *aString;

Asi que:

1

aString = [[NSMutableString alloc] init]; //OK: 

Esto está bien, pero solo en el caso, el astring no apunta a un objeto no válido o perderá una referencia a ese objeto y se filtrará porque no podrá alcanzarlo para liberarlo.

2

aString = [NSMutableString string]; //BAD

Malo porque se supone que debes retener la astring (como lo declaraste de esa manera), no lo estás reteniendo y seguramente obtendrás exc_bad_access en el futuro

3

aString = [[NSMutableString string] retain]; //OK

Igual que el primer enfoque, solo bueno si el astring no apunta a un objeto válido. Sin embargo, usaré el primero.

4

aString = [[[NSMutableString alloc] init] autorelease];//BAD

Igual que el segundo enfoque.

5

self.aString = [[NSMutableString alloc] init]; //BAD!!

Malo porque lo conservas dos veces, por lo tanto, conducirá a fugas de memoria

6

self.aString = [[NSMutableString string]; //******GOOD!******

Este es probablemente el más seguro. El setter de propiedad lo retendrá y, dado que está utilizando el setter, cualquier otro objeto que pueda haber sido señalado por Astring se liberará adecuadamente

7

self.aString = [[NSMutableString string] retain]; //BAD

Esto se retiene dos veces.

8

self.aString = [[[NSMutableString alloc] init] autorelease];//Ok

Esto también está bien, pero usaría el método de conveniencia en lugar de este enfoque largo :)

Tenga cuidado de que las opciones #1 y #3 sean perfectamente buenas si sabe lo que está haciendo. De hecho los uso con mucha más frecuencia que el #6

Personalmente prefiero usar el self. sintaxis. Simplemente hace que sea más fácil determinar que es una variable de instancia, y no solo alguna otra variable en el alcance actual que se perderá cuando se drene su nsautoreleasepool. Sin embargo, es correcto usarlos en ambos sentidos, y si está recibiendo errores exc_bad_access, no es porque lo accediera sin usar self.. Tiene razón al decir que debe asignarlo, y de cualquier forma que elija acceder a sus variables, mantenerlo consistente o recibirá errores.

Espero que esto ayude.

Siempre use accesorios excepto en init, dealloc y en los mismos accesorios. Hacer esto te ahorrará muchos dolores de cabeza como el que estás describiendo. Además, nombre a su ivars algo diferente a su propiedad (_foo, foo_, mFoo, pero no foo).

self.foo es precisamente lo mismo que [self foo]. Llamo al método foo. self.foo = x es precisamente el mismo [self setFoo:x]. Llama al método setFoo:. Si sintetizó la propiedad foo como un retain variable, entonces esto se parece a:

@synthesize foo = foo_;

- (void)setFoo:(id)value {
  [value retain];
  [foo_ release];
  foo_ = value;
}

Esto libera correctamente el antiguo valor de foo_, asigna uno nuevo y lo retiene.

foo = x (asumiendo foo es un ivar) no llama a ningún método. Ninguna. Solo asigna el valor del puntero en x al puntero en foo. Si foo Señaló algo que fue retenido, se filtró. Si el nuevo valor que está asignando no se conserva, se bloqueará más tarde.

La solución a esto es usar siempre accesorios cuando pueda.

O.

El uso de la sintaxis del punto es más limpia (para algunos) y se compila con el equivalente. es decir self.iVar es lo mismo que [self iVar] y self.iVar = aValue es lo mismo que [self setIVar:aValue];

self.aString es un azúcar sintáctico para [self aString]. Sintetizar una propiedad solo cree el -aString y -setAString: Método (dependiendo de la propiedad que la haya elegido sin ser la afectación trivial).

Ahora la pregunta es si usar el . notación. Te sugiero que no lo uses. ¿Por qué? Primero sepa que el objetivo de Objective-C es solo una adición a C. Esto significa que cada código C válido también es un código válido Objective-C.

Ahora mira lo que han hecho con la notación de puntos. La última declaración ya no se mantiene. No distinguirá entre un acceso a un campo de una estructura C y envía un método de Objetivo-C.

Así que por favor no use la notación de puntos. Prefiere usar el [yo ..].

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top