2011-11-20 16 views
23

Tuve algunos debates relacionados con el uso de propiedades y variables de instancia en el trabajo, por lo tanto, me gustaría encontrar una respuesta wiki para eso. Ahora, sé que no hay un tipo de miembro privado real en Objectivo-c, todo es bastante público. Sin embargo, estoy un poco preocupado por la forma en que debemos diseñar nuestras clases y también cumplir con los principios de OOP. Me gustaría escuchar las opiniones de estos tres enfoques de diseño:¿Cómo deben implementarse los miembros privados y públicos en Object-C?

A. De acuerdo con varios correos e incluso a un nuevo curso de desarrollo de iPhone de la Universidad de Stanford, siempre debe usar propiedades donde sea que pueda. Sin embargo, en mi humilde opinión, este enfoque frenará los principios de diseño de OOP porque en este caso, todos los miembros se hacen públicos. ¿Por qué tengo que publicar todas mis variables de instancia internas/locales en el exterior? Además, hay muy poca (pero aún) sobrecarga si usa setters sintetizados a través de propiedades, en lugar de eso, usa directamente ivar local. He aquí una muestra:

//==== header file =====// 
@interface MyClass : NSObject 

@property (nonatomic, retain) NSString *publicMemberWithProperty; 
@property (nonatomic, retain) NSString *propertyForPrivateMember; 

@end 

B. Otro enfoque es declarar Ivars en el archivo de cabecera (sin declarar propiedades relativas) para los miembros privados, y en el mismo archivo de cabecera, para declarar propiedades puros (sin declarar Ivars relativos) para miembros públicos. En tal caso, ivars se usarían directamente en la clase. Este enfoque tiene sentido pero no utiliza todos los beneficios de las propiedades porque tenemos que liberar manualmente los valores anteriores antes de configurar los nuevos. He aquí una muestra:

//==== header file =====// 
@interface MyClass : NSObject{ 
    NSString *_privateMember; 
} 

@property (nonatomic, retain) NSString *publicMemberWithProperty; 

@end 

C. Declarar propiedades puros (sin declarar Ivars relativos) para miembros del público en el archivo de cabecera, y para declarar propiedades puros (sin declarar Ivars relativos) para los miembros privados de interfaz privada en el archivo de aplicación . Este enfoque en mi humilde opinión es más claro que el primero, pero sigue siendo la misma pregunta: ¿por qué tenemos que tener propiedades para miembros internos/locales? He aquí una muestra:

libertad
//==== header file =====// 
@interface MyClass : NSObject 

@property (nonatomic, retain) NSString *publicMemberWithProperty; 

@end 

//==== implementation file =====// 
@interface MyClass() 

@property (nonatomic, retain) NSString *propertyForPrivateMember; 

@end 

Esta decisión me molesta un poco y me gustaría encontrar una confirmación de fuentes respectivas acerca de cómo deben hacerse las cosas. Sin embargo, no pude encontrar declaraciones tan estrictas en los documentos de Apple sobre eso, así que publique un enlace a los documentos de apple si los hay, o a cualquier otra teoría que lo aclare.

+0

Esta pregunta parece ser muy subjetiva e imposible de responder de la manera correcta. – Till

+0

La pregunta es muy simple: ¿cómo deberían implementarse los miembros privados y públicos en Object-C, y donde pude encontrar la voz estricta de Apple al respecto? – Centurion

+1

Propongo diferencias, pero no entraré más en la discusión. Como una pista para probar mi reclamo, se dio cuenta de que, por ejemplo, los cursos de Stanford recomiendan usar propiedades en todas partes. – Till

Respuesta

21

Al utilizar las extensiones de clase, puede tener propiedades privadas.

Una sintaxis extensión de clase es simple:

Dentro del .m-archivo, que tiene la clase, crear una categoría Sin nombre:

.h

@interface OverlayViewController : UIViewController <VSClickWheelViewDelegate> 
- (IBAction)moreButtonClicked:(id)sender; 
- (IBAction)cancelButtonClicked:(id)sender; 
@end 

.m

#import "OverlayViewController.h" 

@interface OverlayViewController() 
@property(nonatomic) NSInteger amount; 
@property(retain,nonatomic)NSArray *colors; 
@end 

@implementation OverlayViewController 
@synthesize amount = amount_; 
@synthesize colors = colors_; 

//… 

@end 

Ahora tiene todos los aspectos de propiedades para miembros privados, sin exponerlos al público. No debe haber sobrecarga a las propiedades sintetizadas a getter/setters escritos, ya que el compilador creará más o menos lo mismo en tiempo de compilación.

Tenga en cuenta que este código utiliza ivars sintetizados. No se necesita ninguna declaración ivar en el encabezado.

Hay un buen cocoawithlove article, acerca de este enfoque.

También pregunta por qué usar propiedades para ivars privados.Hay varias buenas razones:

  • propiedades se ocupan de la propiedad y la gestión de la memoria.
  • en cualquier punto en el futuro puede decidir, escribir un getter/setter personalizado. es decir, para volver a cargar una vista de tabla, una vez que se ha establecido recientemente un Nivar de NSArray. Si utilizó propiedades en consecuencia, no se necesitan otros cambios.
  • Propiedades de compatibilidad con Key Value Coding.
  • public readonly properties can be re-declared to private readwrite properties.

edición
Desde LLVM 3 también es posible, para declarar Ivars en extensiones de clase

@interface OverlayViewController(){ 
    NSInteger amount; 
    NSArray *colors; 
} 
@end 

o incluso en el bloque de aplicación

@implementation OverlayViewController{ 
    NSInteger amount; 
    NSArray *colors; 
} 
//… 
@end 

ver "WWDC2011: Sesión 322 - Advancemen de Objective-C ts en profundidad "(~ 03: 00)

+0

Algunos pedantes señalarán : esos no son estrictamente privados porque los getters y setters pueden ser utilizados por otros códigos si está dispuesto a desafiar una advertencia del compilador, pero en lo que a mí respecta, una advertencia del compilador es suficiente para advertir a los demás. Esta es exactamente la forma (bueno, dar o tomar sus guiones bajos finales) Necesito declaración de variable de instancia en mi equipo - la regla que aplico es que cualquier cosa en el archivo de encabezado es pública por definición. – Tommy

+0

@Tommy: en mi trabajo, algunos chicos argumentaron, por qué tenemos que declarar y usar propiedades para miembros privados. Dijeron que deberíamos usar variables de instancia puras y usarlas directamente en el código de clase. La motivación para hacerlo fue que hay una sobrecarga de procesamiento al usar setter en lugar de liberar el valor antiguo manualmente y asignar un nuevo valor directamente a ivar. Solo por curiosidad, ¿hay alguna declaración "recomendada" de Apple sobre eso? – Centurion

+0

@Centurion Puede usar propiedades "privadas" para [facilitar la administración de la memoria] (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html#//apple_ref/doc/uid/TP40004447-SW4): "A veces puede parecer tedioso o pedante, pero si utiliza los métodos de acceso consistentemente, las posibilidades de tener problemas con la administración de la memoria disminuyen considerablemente. Si está utilizando retener y liberar variables de instancia a lo largo de su código, seguramente estás haciendo lo incorrecto ". – albertamg

2

De forma similar a C++, Objective C proporciona ámbitos públicos, privados y protegidos. También proporciona un alcance de paquete que es similar al alcance del paquete como se define en Java. Las variables públicas de las clases pueden ser referencias en cualquier parte del programa. Las variables privadas solo se pueden referenciar dentro de los mensajes de la clase que lo declara. Se puede usar en mensajes que pertenecen a CUALQUIER instancia de la misma clase. El alcance del paquete es similar al ámbito público dentro de la misma imagen, es decir, ejecutable o biblioteca. De acuerdo con la documentación de Apple, en arquitecturas de 64 bits, las variables del alcance del paquete definidas dentro de una imagen diferente deben tratarse como privadas. El alcance variable se define mediante los modificadores @public, @private, @protected, @package. Estos modificadores se pueden usar de forma similar a C++ o Java. Todas las variables enumeradas en una declaración de ámbito pertenecen al mismo ámbito. Además, las variables se pueden enumerar en la misma línea donde se declara el alcance.

@interface VariableScope : NSObject { 
     @public 
     int iVar0; 
     @protected 
     int iVar1; 
     @private 
     int iVar2; 
     @package 
     int iVar3; 

@public int iVar01, iVar02; 
@protected int iVar11, iVar12; 
@private int iVar21, iVar22; 
@package int iVar31, iVar32; 
} 
    @end 

Para más información utilice el siguiente enlace

http://cocoacast.com/?q=node/100

+4

Sí, hay palabras clave como público, privado y protegido, pero no limitan el alcance durante el tiempo de ejecución. He realizado algunas pruebas, y puedo decir que en objetivo-c todos los miembros son bastante públicos. Puede encontrar la publicación sobre mi experimento aquí: http://stackoverflow.com/questions/6122398/objective-c-why-private-ivars-are-not-hidden-from-the-outside-access-when-using – Centurion

3

No hay realmente un lugar limpio, seguro, ninguna perdida, solución a este que es apoyado directamente por el lenguaje. Muchas personas se contentan con las funciones de visibilidad actuales, mientras que muchas sienten que les falta.

El tiempo de ejecución podría (pero no lo hace) hacer esta distinción con ivars y métodos. El apoyo de primera clase sería lo mejor, IMO. Hasta entonces, tenemos algunos modismos de abstracción:

Opción A

es malo - todo es visible. No estoy de acuerdo en que sea un buen enfoque, y eso no es OOD (IMO).Si todo es visible, entonces su clase deberán:

  • apoyo todos los casos de cómo el cliente puede usar su clase (por lo general no razonables o indeseables)
  • o se les proporcione una tonelada de reglas a través de la documentación (doc las actualizaciones son propensos a pasar desapercibido)
  • o los descriptores de acceso deben tener ningún efecto secundario (no OOD, y traduce con frecuencia para 'no anulan los descriptores de acceso')

Opción B

Tiene las deficiencias de la Opción A ,, y como la Opción A, se puede acceder a los miembros por clave.

Opción C

Esto es un poco más seguro. Al igual que todos los demás, aún puede usar el acceso con clave, y las subclases pueden anular sus accesos (incluso si no lo sabe).

Opción D

Un enfoque para esto es para escribir su clase como un envoltorio de más de más de un tipo de aplicación. Puede usar un tipo ObjC o un tipo C++ para esto. Puede favorecer C++ donde la velocidad es importante (se mencionó en el OP).

Un enfoque simple para esto tomaría una de las formas:

// inner ObjC type 
@class MONObjectImp; 

@interface MONObject : NSObject 
{ 
@private 
MONObjectImp * imp; 
} 
@end 


// Inner C++ type - Variant A 
class MONObjectImp { ... }; 

@interface MONObject : NSObject 
{ 
@private 
MONObjectImp imp; 
} 
@end 


// Inner C++ type - Variant B 
class MONObjectImp; 

@interface MONObject : NSObject 
{ 
@private 
MON::t_auto_pointer<MONObjectImp> imp; 
} 
@end 

(Nota:. Puesto que esto fue escrito originalmente, se ha introducido la posibilidad de declarar Ivars en el bloque @implementation puede declarar las C++ tipos allí si no es necesario para soportar cadenas de herramientas más antiguas o el 'frágil' 32 bits OS X ABI).

C++ La variante A no es tan 'segura' como las demás, porque requiere la declaración de clase visible para el cliente. En los otros casos, puede declarar y definir la clase Imp en el archivo de implementación, ocultándolo de los clientes.

A continuación, puede exponer la interfaz que elija. Por supuesto, los clientes aún pueden acceder a sus miembros si realmente lo desean a través del tiempo de ejecución. Esto sería más fácil para ellos hacer de manera segura con el tipo ObjC Imp - el tiempo de ejecución objc no es compatible con la semántica de C++ para los miembros, por lo que los clientes pedirían UB (IOW es todo POD para el tiempo de ejecución).

El costo de tiempo de ejecución para la implementación de ObjC es escribir un nuevo tipo, crear una nueva instancia de Imp para cada instancia y una buena cantidad de doblaje de mensajes.

El tipo C++ no costará prácticamente nada, aparte de la asignación (Variante B).

Opción E

Otros enfoques a menudo se disocian Ivars de interfaces. Mientras que esto es bueno, también es muy inusual para los tipos ObjC. Los tipos/diseños de ObjC a menudo mantienen una relación estrecha con sus ivars y sus accesorios, por lo que enfrentarás la resistencia de otros desarrolladores.

Cuestiones relacionadas