2009-08-26 15 views
5

Este pequeño sintaxis me ha resultado un poco confuso en Objective-C.Objective-C: Cuándo invocar self.myObject versus simplemente llamar a myObject

¿Cuándo debería llamar a self.myObject solo llamando a myObject?

Parece redundante, pero no son intercambiables.

¿Alguien podría aclararme?

+0

Encontré una publicación similar aquí: http://stackoverflow.com/questions/1051543/should-i-use-self-keyword-properties-in-the-implementation – Jonah

Respuesta

8

Si solo está accediendo a ellos, no hay muchas razones para usar self.member. Si está haciendo una tarea, es bueno si está haciendo algo más que el simple parámetro @property (assign), por ejemplo, retener, copiar, etc., para que pueda guardar el código que está escribiendo. Un ejemplo:

myObject = anotherObject; 
self.myObject = anotherObject; 

La segunda opción se asegurará de que en realidad estás asignando el objeto de la manera deseada (obtener una copia, el aumento de la cuenta de retención, etc.). No es diferente de [self setMyObject:anotherObject].

Dado que la notación de puntos se sustituye por un mensaje del compilador (similar al x[5] que se convierte en *(x + 5*sizeof(x)) en el trabajo de matriz normal), no hay sobrecarga ni eficacia adicional al usar notación de puntos en los mensajes normales.

1

Casi nunca debe llamar a los usuarios de acceso a la propiedad desde la implementación de la misma clase. Los métodos de instancia de la clase tienen acceso conveniente al estado interno, por lo que normalmente tiene sentido acceder a ese estado directamente.

Si está utilizando accesorios sintetizados, llamarlos solo agrega (probablemente) una sobrecarga innecesaria. Si los accesadores tienen una implementación más complicada, entonces estás oscureciendo el propósito del código.

Finalmente, algunas personas que son nuevas en Objective-C usan la sintaxis de autopropiedad y los accesorios sintetizados para tratar de evitar tener que entender la administración de la memoria Cocoa. Realmente necesita aprender cómo funciona, por lo que tratar de evitarlo es contraproducente.

+0

Solo porque puedes jugar con el estado interno del objeto todo lo que quiera o no significa que no deberías. Y solo porque comprenda cómo funciona la gestión de la memoria no significa que lo hará a la perfección todo el equipo. Duplicar su responsabilidad de administración de memoria entre un montón de métodos es pedir errores. – Chuck

+0

Estoy respetuosamente en desacuerdo. Si sus clases tienen muchos accesadores sintetizados, entonces probablemente estén mal diseñados. Si ha implementado accesadores no triviales, entonces debe tener cuidado al usarlos adecuadamente. Los descriptores de acceso a propiedades están destinados a ser utilizados para crear una interfaz * externa * para su clase. a veces, tiene sentido que su clase use internamente su interfaz externa, pero a menudo eso es innecesario (o contraproducente). –

+0

En cualquier caso, si realmente desea usar los accesos, entonces use el "sí mismo". la sintaxis simplemente oculta lo que está pasando, por lo que debe usar mensajes explícitos de todos modos. Si está configurando una propiedad, "[self setFoo: value]" tiene solo 5 caracteres más que "self.foo = value". Para el acceso de lectura, la diferencia es aún menor. Solo escribirá el código una vez, por lo que debe intentar aclarar lo que sucede cuando usted (u otra persona) lo lea más tarde. –

1

Si está utilizando Core Data, siempre debe usar los accessors, ya que algunas propiedades pueden no cargarse desde el almacén persistente hasta que sea necesario. (Suponiendo que estés usando una tienda de SQLite, de todos modos.)

Si usted no está utilizando la base de datos, usted es generalmente seguro de usar sólo myObject directamente si estás única lectura el valor. Si está modificando el valor de myObject, debe usar los accesorios para asegurarse de que cualquier otro objeto que observe el valor de esa propiedad reciba una notificación adecuada. En otras palabras:

// Not changing the value of myObject, so no accessor needed 
[someMutableArray addObject:myObject]; 

// Changes the value, so you need to use the accessor 
self.myObject = newObject;  
[self setMyObject:newObject]; // Exactly identical to the previous line. 

En general, sin embargo, hay muy poca sobrecarga; Prefiero usar siempre los accesos, incluso dentro del mismo objeto. (Por supuesto, está el argumento sobre el uso de ellos en los inicializadores, pero eso es un problema aparte.)

3

Hrm, no puedo decir que estoy de acuerdo con Mark o Cinder6.

Bueno, estoy de acuerdo en la primera parte. :-) self.foo está invocando el método -foo. Plain foo está accediendo al foo ivar.

En la mayoría de los casos, siempre debe seguir sus métodos.Están ahí para abstraerte del almacenamiento real y lejos de cualquier otro comportamiento que pueda ser necesario. Piensa en lo que sucederá si luego subclasificaste tu clase. En su mayor parte, desea llamar sus propios métodos públicos en los lugares donde accede a la funcionalidad que cubren.

La excepción se encuentra en el inicio y el desmontaje de objetos, y dentro de los mismos accesores de propiedades cuando no los sintetiza. Durante el inicio y el desmontaje del objeto, usted hace no desea invocar implementaciones de métodos de subclase, porque esos métodos no deberían tener que tratar con su objeto en su estado parcialmente configurado.

0

No hay respuesta de corte y secado. Sin embargo, recuerde que la optimización prematura es mala. En Cocoa en la Mac, o en el iPhone, se requiere que el uso de accesadores/propiedades sea compatible con KVO. La conformidad de KVO es necesaria para que los datos centrales y los enlaces de cacao funcionen automáticamente. En Core Data, no solo es necesario garantizar KVO al modificar las propiedades, sino también al acceder a ellas.

También es mejor utilizar accesos/propiedades cuando desea garantizar el comportamiento de administración de la memoria de propiedades, es decir, siempre al establecer un ivar para usar la notación de establecimiento o punto, y dependiendo de qué patrón de gestión de memoria siga , para usar siempre accesos/propiedades al obtener un ivar.

Existen varios patrones de administración de memoria diferentes. Todos los no rotos garantizan que un objeto devuelto por un descriptor de acceso sobrevivirá al menos hasta el final del alcance de liberación automática actual. Es decir, el objeto se retiene explícitamente y se libera automáticamente en el ámbito de liberación automática actual. El método recomendado por Apple hace esto de manera explícita en el captador:

- (id)foo {return [[foo retain] autorelease]; } 
- (void)setFoo:(id)aFoo { 
    if(! [aFoo isEqual:foo]) { 
    [foo release]; 
    foo = [aFoo retain]; 
    } 
} 

Queda implícito que es el patrón que siguen en sus descriptores de acceso sintetizados. En lo personal, prefiero AutoRelease en la incubadora:

- (id)foo {return foo;} 
- (void)setFoo:(id)aFoo { 
    [foo autorelease]; 
    foo = [aFoo retain]; 
} 

Este autoreleasees el valor anterior antes de reemplazarlo con el nuevo valor. Esto tiene exactamente el mismo efecto que retener y autorrellenar en el captador, pero requiere que el objeto solo se agregue a un grupo de autorrelease una vez. La mayoría de las veces tiene un conteo retenido de uno y no se libera automáticamente, por lo que no irá a ningún lado sin importar lo que suceda. Si la propiedad se reemplaza durante algún código que aún se mantiene (como en una devolución de llamada delegada), no desaparecerá de debajo.

Lo que esto significa es que el uso de accesadores/propiedades le dará la confianza de que sus objetos estarán disponibles todo el tiempo que lo necesite sin que otra parte del código los libere.

La última y mejor razón para usar siempre accessors/properties es que hace una suposición menos para cada propiedad: que hay un ivar subyacente para esa propiedad, y que tiene el mismo nombre (supongo que son dos suposiciones) . Tal vez en el futuro desee reemplazar un ivar con un descriptor de acceso derivado. La notación de propiedades seguirá funcionando. Quizás quieras renombrar el ivar; la propiedad seguirá funcionando. Afortunadamente, se puede confiar en la refactorización en Xcode, pero ¿por qué molestarse?

El objetivo de la programación orientada a objetos es utilizar las interfaces definidas en la clase. No hay una buena razón (aunque hay muchas perjudiciales y racionalizadas) para que una clase ignore su propia interfaz. Todos los métodos, excepto los usuarios mismos, deberían, en el caso general, tratar el objeto como sacrosanto y su estado interno como privado. Escriba cada método como si estuviera en una categoría o en una subclase, y trate a ivars como un estado privado, a menos que el diseño específico necesite instrucciones directas de lo contrario. Hay muchas buenas razones para acceder directamente a los ivars, pero se determinan caso por caso.

+0

Sus métodos getter/setter no son idénticos a los de Apple. Su getter es básicamente el que usaría para una propiedad "assign" y el setter es para una propiedad "retener". Estoy seguro de que funciona la mayor parte del tiempo, pero creo que se despegará si comienzas a usar tus propios grupos de liberación automática. Lo mejor es seguir las convenciones utilizadas en el resto de Cocoa. –

Cuestiones relacionadas