2012-03-22 15 views
27

Estoy haciendo una aplicación, y tengo una clase con muchas propiedades y me preguntaba si era posible darles un valor predeterminado. Porque si hago un método init, que es un montón de trabajo para escribir todo, hay una gran posibilidad de error tipográfico y es simplemente no es agradable codificación ...Objective-C establece el valor predeterminado para una propiedad

Este es el aspecto de mi clase como:

// Goalkeeping attributes 
@property (nonatomic) int aerialAbility; 
@property (nonatomic) int commandOfArea; 
@property (nonatomic) int communication; 
@property (nonatomic) int eccentricity; 
@property (nonatomic) int handling; 
@property (nonatomic) int kicking; 
@property (nonatomic) int oneOnOnes; 
@property (nonatomic) int reflexes; 
@property (nonatomic) int rushingOut; 
@property (nonatomic) int tendencyToPunch; 
@property (nonatomic) int throwing; 

// Technical attributes 
@property (nonatomic) int corners; 
@property (nonatomic) int crossing; 
@property (nonatomic) int dribbling; 
@property (nonatomic) int finishing; 
@property (nonatomic) int firstTouch; 
@property (nonatomic) int freeKickTaking; 
@property (nonatomic) int heading; 
@property (nonatomic) int longShots; 
@property (nonatomic) int longThrows; 
@property (nonatomic) int marking; 
@property (nonatomic) int passing; 
@property (nonatomic) int penaltyTaking; 
@property (nonatomic) int tackling; 
@property (nonatomic) int technique; 

// Mental attributes 
@property (nonatomic) int aggression; 
@property (nonatomic) int anticipation; 
@property (nonatomic) int bravery; 
@property (nonatomic) int composure; 
@property (nonatomic) int concentration; 
@property (nonatomic) int creativity; 
@property (nonatomic) int decisions; 
@property (nonatomic) int determination; 
@property (nonatomic) int flair; 
@property (nonatomic) int influence; 
@property (nonatomic) int offTheBall; 
@property (nonatomic) int positioning; 
@property (nonatomic) int teamwork; 
@property (nonatomic) int workRate; 

// Physical attributes 
@property (nonatomic) int acceleration; 
@property (nonatomic) int agility; 
@property (nonatomic) int balance; 
@property (nonatomic) int jumping; 
@property (nonatomic) int naturalFitness; 
@property (nonatomic) int pace; 
@property (nonatomic) int stamina; 
@property (nonatomic) int strength; 

Así pues, en la implementación, lo estoy haciendo algo como:

@synthesize aerialAbility = _aerialAbility; 

y me preguntaba si sería posible hacer esto:

@interface MyClass : NSObject 
@property (nonatomic) int someProperty; 

@end 

@implementation MyClass 
@synthesize someProperty = _someProperty = 10; 
@end 

Sé que esto no funcionará, y esto no funciona en absoluto, pero me preguntaba si hay alguna manera de hacer algo como esto.

Al igual que en Java se puede:

class MyClass 
{ 
private int someProperty = 10; 
public int getSomeProperty(){return someProperty;} 
public void setSomeProperty(int someProperty){this.someProperty = someProperty;} 
} 

Respuesta

39

nunca he visto este comportamiento antes, pero estoy bastante seguro de que esto es lo que el paso de inicio es para cuando la asignación de un objeto, es decir la definición de variables e inicializar el objeto.

-(id)init { 
    if (self = [super init]) { 
     self.someProperty = 10; 
    } 
    return self; 
} 

Y la llamada de esta manera:

MyClass* test = [[MyClass alloc] init]; 

Observe que puede tener más de una función init, que le permite tener un par de conjuntos diferentes de valores por defecto.

Lo que @synthesize hace es decirle al precompilador que debe generar el código para el conjunto/obtener, no establecer el valor de la propiedad. El '=' simplemente le dice al precontenedor que, aunque el nombre de la variable y la propiedad no son los mismos, deben estar conectados.

Además, como una opinión personal (no relacionada con la pregunta en absoluto), este objeto parece demasiado grande y es posible que pueda dividirlo de alguna manera o hacer lo que sugirió otra persona. ¿Tal vez esta clase podría heredar de algunas otras clases para darle las diferentes propiedades que necesita? Como dije, simplemente una sugerencia ya que no sé cómo se ve el otro código :)

+1

Así es - el inicializador es una multa lugar para configurar el valor inicial para un ivar o propiedad. Más específicamente, el inicializador designado (el inicializador que llamará cualquier otro inicializador para la clase) es aquel en el que debe configurar esos valores. – Caleb

+0

Gracias por las sugerencias, sin embargo, trato de evitar poner más de 30 tareas en el inicializador, y la clase no puede dividirse (por supuesto, siempre puede, pero solo empeoraría el diseño de mi clase)) –

+0

por qué querría evitar eso que no entiendo. El init está hecho para este propósito, o puedes usar un Dictionary que deberías configurar en el init de todos modos ... – chikuba

9

Para un número tan grande de atributos como ese, estaría inclinado a almacenar los datos como un diccionario en lugar de propiedades individuales, y lo haría almacenar los valores predeterminados en una lista de propiedades. NSDictionary objetos se pueden inicializar con un prope rty lista fácilmente

Si el uso de un diccionario no es de su gusto, aún almacenaría los valores predeterminados en una lista de propiedades, y en el inicializador designado, haría un bucle sobre los elementos de la lista de propiedades y los aplicaré al self usando la tecla codificación de valor. Debe tener en cuenta que esto solo es apropiado para datos confiables, no datos proporcionados por el usuario, ya que de lo contrario podrían ser secuestrados para establecer otras propiedades que no está esperando.

+1

+1, y el diccionario será más fácil de extender y cambiar más tarde, también. –

+0

Pero, ¿qué ocurre si quiere almacenar propiedades de tipo mixto en el diccionario? – To1ne

+0

@ To1ne Eso no debería ser un problema. NSDictionary no aplica seguridad de tipo. Puede almacenar muchos tipos de objetos. – mtmurdock

4

No hay está incorporado en forma similar a Java de inicializar propiedades sintetizados o Ivars en Objective C. Sin embargo, ya que sus propiedades se ven casi idénticos, es posible que desee considerar haciéndolos @dynamic en lugar de sintetizarlos.

De seguro, necesitaría escribir dos métodos de aspecto aterrador (here is a nice and clean example), pero a cambio obtendrá una forma uniforme de almacenar sus propiedades como objetos dentro de NSMutableDictionary. Esto abre varias alternativas interesantes que no están disponibles con ivars simples: puede diferir la inicialización de sus propiedades hasta que sean necesarias, puede proporcionar valores predeterminados para propiedades no configuradas, o puede inicializar sus propiedades "al por mayor" completando el diccionario con valores para sus llaves.

+0

Parece interesante, voy a ver eso mañana, gracias! –

0

La sugerencia del diccionario anterior es buena. A veces he utilizado objetos de configuración específicos:

@interface GoalKeepingAttributes 
@property (nonatomic) int agression 
@property (nonatomic) int ... etc 
@end 

@implementation GoalKeepingAttributes 
@end 

etc. Si es necesario, esta clase podría tener un método init que establece un montón de valores y los valores predeterminados.

Probablemente también pueda usar una estructura de estilo c, ya que son simplemente primitivas.

Es cierto que esto es simplemente aplazando el problema, moviendo la inicialización de la clase para la clase de configuración, pero:

  • que tendría que hacer esto con un diccionario de todos modos
  • que pueda comentar los ajustes de configuración
  • victoria más importante: la clase de configuración es fuertemente tipado, que captura los errores en tiempo de compilación, permite la finalización de código Xcode

se podría dividir el configuraciones en diferentes tipos (Portero, Técnico y Mental). De nuevo, solo está dividiendo el problema, pero eso puede ayudar a mantener las cosas enfocadas.

0

Otra posibilidad sería anular los getters predeterminados para las propiedades. En sus captadores, puede ver si los valores fueron inicializados y, de no ser así, devolver su valor predeterminado. (Que funcione para algunos tipos de propiedad, pero no para otros, claramente - que necesita el valor por defecto que será uno que indica que se ha establecido ningún valor.)

0
- (id)init 
{ 
    self = [super init]; 
    if (self != nil) { 
     [self commonInit]; 
    } 

    return self; 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self != nil) { 
     [self commonInit]; 
    } 

    return self; 
} 

-(instancetype)initWithCoder:(NSCoder *)aDecoder { //nib init 
    self = [super initWithCoder:aDecoder]; 
    if (self != nil) { 
     [self commonInit]; 
    } 
    return self; 
} 

Es posible ajustar el valor por defecto y hacer la lógica predeterminada en commonInit función si el objeto es una vista. Si no es vista, puede hacerlo en la función init en mi opinión.

0

Sí, puede anular getter en caso de establecer el valor predeterminado antes de iniciar la propiedad.

Por ejemplo, definir la propiedad en el archivo .h:

@interface MySegmentedControl : UISegmentedControl 
@property (assign, nonatomic) CGFloat systemFontOfSize; 
@end 

y anular captador y el valor predeterminado establecido en ejecución en el archivo .m:

@implementation MySegmentedControl  
-(CGFloat) systemFontOfSize 
{ 
    return _systemFontOfSize ? _systemFontOfSize : 17.0f; 
}  
@end 
Cuestiones relacionadas