¿Hay alguna diferencia entre una "variable de instancia" y una "propiedad" en Objective-c?

82

¿Hay alguna diferencia entre una "variable de instancia" y una "propiedad" en Objective-c?

No estoy muy seguro de esto. Creo que una "propiedad" es una variable de instancia que tiene métodos de acceso, pero podría pensar mal.

Gracias
fuente

Respuestas:

84

Una propiedad es un concepto más abstracto. Una variable de instancia es literalmente solo una ranura de almacenamiento, como una ranura en una estructura. Normalmente, se supone que otros objetos nunca deben acceder a ellos directamente. Una propiedad, por otro lado, es un atributo de su objeto al que se puede acceder (suena vago y se supone que debe hacerlo). Por lo general, una propiedad devolverá o establecerá una variable de instancia, pero podría usar datos de varias o ninguna. Por ejemplo:

@interface Person : NSObject {
    NSString *name;
}

    @property(copy) NSString *name;
    @property(copy) NSString *firstName;
    @property(copy) NSString *lastName;
@end

@implementation Person
    @synthesize name;

    - (NSString *)firstName {
        [[name componentsSeparatedByString:@" "] objectAtIndex:0];
    }
    - (NSString *)lastName {
        [[name componentsSeparatedByString:@" "] lastObject];
    }
    - (NSString *)setFirstName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
    - (NSString *)setLastName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
@end

(Nota: El código anterior tiene errores, ya que asume que el nombre ya existe y tiene al menos dos componentes (por ejemplo, "Bill Gates" en lugar de solo "Gates"). Sentí que corregir esas suposiciones haría que el verdadero objetivo del código menos claro, así que solo lo señalo aquí para que nadie repita inocentemente esos errores).

Arrojar
fuente
4
La forma en que he estado viendo las propiedades es un medio para proporcionar / restringir el acceso a las variables de instancia para objetos externos. ¿Algo así como el concepto público / privado en otros idiomas?
prototipo
"Normalmente, se supone que otros objetos nunca deben acceder a ellos directamente" ¿Qué quieres decir con esto? ¿También se actualiza su respuesta con el moderno objetivo-c?
Miel
1
@Honey Creo que se refiere al concepto de encapsulación y sigue las mejores prácticas. Otros objetos no deberían poder acceder o modificar directamente el ivar. Al controlar el acceso a ivar a través de propiedades, podemos interceptar esas llamadas antes de que afecten potencialmente al ivar. Consulte aquí para obtener más información: en.wikipedia.org/wiki/Encapsulation_(computer_programming)
user3344977
33

Una propiedad es una forma amigable de implementar un getter / setter para algún valor, con características y sintaxis útiles adicionales. Una propiedad puede estar respaldada por una variable de instancia, pero también puede definir el getter / setter para hacer algo un poco más dinámico, por ejemplo, puede definir una propiedad lowerCase en una cadena que crea dinámicamente el resultado en lugar de devolver el valor de algún miembro. variable.

He aquí un ejemplo:

// === In your .h ===

@interface MyObject {
    NSString *propertyName;

}

// ...

@property (nonatomic, retain) NSString *propertyName;

// === In your .m @implementation ===

@synthesize propertyName /* = otherVarName */;

La @propertylínea define una propiedad llamada propertyNamede tipo NSString *. Esto se puede obtener / configurar usando la siguiente sintaxis:

myObject.propertyName = @"Hello World!";
NSLog("Value: %@", myObject.propertyName);

Cuando asigna o lee de myObject.propertyName, realmente está llamando a métodos setter / getter en el objeto.

La @synthesizelínea le dice al compilador que genere estos getter / setters por usted, usando la variable miembro con el mismo nombre de la propiedad para almacenar el valor (o otherVarNamesi usa la sintaxis en los comentarios).

Junto con @synthesize, aún puede anular uno de los getter / setters definiendo el suyo. La convención de nomenclatura para estos métodos es setPropertyName:para el setter y propertyName(o getPropertyNameno estándar) para el getter. El otro todavía se generará para ti.

En su @propertylínea, puede definir una serie de atributos en parens para la propiedad que pueden automatizar cosas como la seguridad de subprocesos y la gestión de memoria. Por defecto, una propiedad es atómica, lo que significa que el compilador ajustará las @synthesizllamadas get / set con los bloqueos adecuados para evitar problemas de concurrencia. Puede especificar el nonatomicatributo para deshabilitarlo (por ejemplo, en el iPhone al que desea asignar la mayoría de las propiedades por defecto nonatomic).

Hay 3 valores de atributo que controlan la gestión de la memoria para cualquier @synthesizedconfigurador. La primera es la retainque se enviará automáticamente releasea los valores antiguos de la propiedad y retaina los nuevos valores. Esto es muy útil.

El segundo es copyque hará una copia de los valores pasados ​​en lugar de retenerlos. Es una buena práctica usar copypara NSString porque una persona que llama podría pasar un NSMutableString y cambiarlo por debajo de usted. copyhará una nueva copia de la entrada a la que solo usted tiene acceso.

El tercero es assigncuál asigna un puntero directo sin llamar a retener / liberar en el objeto antiguo o nuevo.

Por último, también puede utilizar el readonlyatributo para deshabilitar el establecedor de la propiedad.

Mike Weller
fuente
1
¿Existe algún beneficio al declarar la variable de instancia y la propiedad (por ejemplo, propertyName)? La declaración dentro de la interfaz no es necesaria si declara una propiedad para la misma variable, ¿correcto? Esto realmente ahorra en líneas de código, a menos que haya algo que me falta ..
whyoz
6

Utilizo propiedades para la parte de la interfaz, donde el objeto interactúa con otros objetos y las variables de instancia son cosas que necesita dentro de su clase, se supone que nadie más que usted debe verlas y manipularlas.

Jens Busch
fuente
3

De forma predeterminada, una propiedad de lectura y escritura estará respaldada por una variable de instancia, que nuevamente será sintetizada automáticamente por el compilador.

Una variable de instancia es una variable que existe y mantiene su valor durante la vida del objeto. La memoria utilizada para las variables de ejemplo se asigna cuando el objeto se crea por primera vez (a través de alloc) y se libera cuando el objeto se desasigna.

A menos que especifique lo contrario, la variable de instancia sintetizada tiene el mismo nombre que la propiedad, pero con un prefijo de subrayado. Para una propiedad llamada firstName, por ejemplo, la variable de instancia sintetizada se llamará _firstName.

jitenagarwal19
fuente
2

Anteriormente, la gente usaba propiedades públicamente y ivars para uso privado, pero desde hace varios años, también puede definir propiedades @implementationpara usarlas de forma privada. Pero todavía usaría ivars cuando sea posible, ya que hay menos letras para escribir y se ejecuta más rápido de acuerdo con este artículo . Tiene sentido ya que las propiedades están destinadas a ser "pesadas": se supone que se debe acceder a ellas desde getters / setters generados o desde los escritos manualmente.

Sin embargo, en los códigos recientes de Apple, los ivars ya no se utilizan. Supongo que porque es más como objclugar de C/C++, además de que es más fácil de usar con propiedades assign, nullableetc.

superarts.org
fuente
Supongo que el uso de propiedades por parte de Apple @implementationquiere mostrar similitudes con Swift. Aún así, también prefiero respaldar variables para no desperdiciar una llamada de función virtual para buscar un campo simple de mi propia clase (y eso sucede cuando se accede a la propiedad).
Leo