简体   繁体   中英

Objective-C set default value for a property

I'm making an app, and I have a class with quite a lot properties and I was wondering if it was possible to give them a default value. Because if I make an init method, it's a lot of work to type everything, there's a big chance of typo's and it's just not nice coding...

This is how my class looks like:

// 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;

So then, in the implementation, I'm doing something like:

@synthesize aerialAbility = _aerialAbility;

And I was wondering if it would be possible to do this:

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

@end

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

I know this won't work, and this doesn't right at all, but I was wondering if there's a way to do something like this.

Like in java you can:

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

I have never seen this behavior before but I'm pretty sure this is what the init step is for when allocation an object, that is setting variables and initializing the object.

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

And the call it like this:

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

Notice that you can have more than one init function which allows you to have a few different sets of default values.

What @synthesize does is tell the precompiler that it should generate the code for the set/get, not set the value of the property. The '=" just tells the precomplier that, even though the name of the variable and the property are not the same, they should be connected.

Also, as a personal opinion (not realated to the question at all), this object seems way to big and you might be able to split it up in some way or do like other person suggested. Maybe this class could inherit from a few other classes to give it the different properties it needs? As I said, it just a suggestion since I don't know what your other code looks like :)

For such a large number of attributes like that, I'd be inclined to store the data as a dictionary rather than individual properties, and I would store the defaults in a property list. NSDictionary objects can be initialised with a property list easily.

If using a dictionary is not to your tastes, I'd still store the defaults in a property list, and in the designated initialiser, I would loop over the items in the property list and apply them to self using key-value coding. You should note that this is only appropriate for trusted data, not user-supplied data, as it could otherwise be hijacked to set other properties that you aren't expecting.

There is no built-in Java-like way of initializing synthesized properties or ivars in Objective C. However, since your properties look almost identical, you might want to consider making them @dynamic instead of synthesizing them.

For sure, you would need to write two scary-looking methods ( here is a nice and clean example for you), but in return you get a uniform way of storing your properties as objects inside NSMutableDictionary . This opens up several interesting alternatives not available with plain ivars: you could defer initialization of your properties until they are needed, you could provide default values for unset properties, or you could initialize your properties "wholesale" by filling in the dictionary with values for their keys.

Yes, you can override getter in case to set default value before property was inited.

For example, define property in .h file:

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

and override getter and set default value under implementation in .m file:

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

The dictionary suggestion above is a good one. I've sometimes used dedicated configuration objects:

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

@implementation GoalKeepingAttributes
@end

etc. If needed, this class could have an init method that sets a bunch of values and defaults.

You could probably use a c-style struct as well, since these are just primitives.

It's true that this is merely deferring the problem, moving the initialization from the one class to the config class, but:

  • you'd have to do this with a dictionary anyway
  • you can comment the config settings
  • biggest win: the config class is strongly typed, which catches errors at compile time, allows for xcode code completion

You could split up the configurations into different types (Goalkeeping, Technical, and Mental). Again, it's just splitting up the problem, but that can help keeping things focused.

Another possibility would be to override the default getters for the properties. In your getters, you can look to see if the values were initialized and, if not, return your default value. (That would work for some property types but not for others, clearly - you need the default value to be one that indicates that no value was set.)

- (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;
}

You can set default value and do default logic in commonInit function if the object is a view. If it's not view, you can do it in the init function in my opinion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM