Objective-C设置属性的默认值。

时间:2021-08-12 18:36:32

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...

我在做一个应用,我有一个有很多属性的类,我想知道是否可以给它们一个默认值。因为如果我创建一个init方法,那么要输入所有东西就需要大量的工作,所以很有可能会出现错码,而且这不是很好的编码……

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:

就像在java中,你可以:

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

7 个解决方案

#1


40  

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.

请注意,您可以拥有多个init函数,它允许您拥有一些不同的默认值集。

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.

@synthesize会告诉预编译器它应该为set/get生成代码,而不是设置属性的值。'="只是告诉预编译器,即使变量的名称和属性不相同,它们也应该被连接。

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 :)

同样,作为个人观点(完全不涉及问题),这个对象似乎非常大,你可能可以以某种方式将它分割开来,或者按照其他人的建议去做。也许这个类可以从其他几个类继承来提供它需要的不同属性?就像我说的,这只是一个建议,因为我不知道你的其他代码是什么样子的:

#2


9  

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.

对于如此多的属性,我倾向于将数据存储为字典而不是单个属性,并将默认值存储在属性列表中。NSDictionary对象可以使用属性列表轻松初始化。

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.

如果使用字典不符合您的口味,我仍然将默认值存储在属性列表中,在指定的initialiser中,我将对属性列表中的项进行循环,并使用键-值编码将它们应用到self。您应该注意,这只适用于受信任的数据,而不适用于用户提供的数据,因为如果不这样做,它可能会被劫持来设置您不希望的其他属性。

#3


4  

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.

在Objective c中没有类似于java的初始化合成属性或ivars的方法,但是,由于您的属性看起来几乎是相同的,您可能需要考虑使它们成为@dynamic而不是合成它们。

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.

当然,您需要编写两个看起来很可怕的方法(这里有一个很好的、干净的示例),但是作为回报,您将获得一种统一的方法,将属性存储为NSMutableDictionary中的对象。这为普通ivars提供了几个有趣的替代方案:您可以将属性的初始化延迟到需要时,您可以为未设置的属性提供默认值,或者您可以通过在字典中填充它们的键值来初始化属性“批发”。

#4


0  

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.

如果需要,这个类可以有一个init方法,它设置一些值和默认值。

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

您也可以使用c风格的结构体,因为这些只是原语。

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
  • 最大的好处:配置类是强类型的,它在编译时捕获错误,允许xcode代码完成

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.

您可以将配置分解为不同的类型(门将、技术和心理)。同样,这只是解决问题,但这可以帮助你集中注意力。

#5


0  

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.)

另一种可能是覆盖属性的默认getter。在getter中,您可以查看这些值是否已初始化,如果未初始化,则返回默认值。(这对某些属性类型有效,但对其他类型无效——显然,您需要默认值是表示没有设置值的值。)

#6


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

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.

如果对象是视图,可以在commonInit函数中设置默认值并执行默认逻辑。如果不是视图,你可以在init函数中实现。

#7


0  

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

是的,您可以重写getter,以防在属性输入之前设置默认值。

For example, define property in .h file:

例如,在.h文件中定义属性:

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

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

并在.m文件中覆盖getter和设置默认值:

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

#1


40  

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.

请注意,您可以拥有多个init函数,它允许您拥有一些不同的默认值集。

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.

@synthesize会告诉预编译器它应该为set/get生成代码,而不是设置属性的值。'="只是告诉预编译器,即使变量的名称和属性不相同,它们也应该被连接。

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 :)

同样,作为个人观点(完全不涉及问题),这个对象似乎非常大,你可能可以以某种方式将它分割开来,或者按照其他人的建议去做。也许这个类可以从其他几个类继承来提供它需要的不同属性?就像我说的,这只是一个建议,因为我不知道你的其他代码是什么样子的:

#2


9  

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.

对于如此多的属性,我倾向于将数据存储为字典而不是单个属性,并将默认值存储在属性列表中。NSDictionary对象可以使用属性列表轻松初始化。

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.

如果使用字典不符合您的口味,我仍然将默认值存储在属性列表中,在指定的initialiser中,我将对属性列表中的项进行循环,并使用键-值编码将它们应用到self。您应该注意,这只适用于受信任的数据,而不适用于用户提供的数据,因为如果不这样做,它可能会被劫持来设置您不希望的其他属性。

#3


4  

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.

在Objective c中没有类似于java的初始化合成属性或ivars的方法,但是,由于您的属性看起来几乎是相同的,您可能需要考虑使它们成为@dynamic而不是合成它们。

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.

当然,您需要编写两个看起来很可怕的方法(这里有一个很好的、干净的示例),但是作为回报,您将获得一种统一的方法,将属性存储为NSMutableDictionary中的对象。这为普通ivars提供了几个有趣的替代方案:您可以将属性的初始化延迟到需要时,您可以为未设置的属性提供默认值,或者您可以通过在字典中填充它们的键值来初始化属性“批发”。

#4


0  

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.

如果需要,这个类可以有一个init方法,它设置一些值和默认值。

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

您也可以使用c风格的结构体,因为这些只是原语。

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
  • 最大的好处:配置类是强类型的,它在编译时捕获错误,允许xcode代码完成

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.

您可以将配置分解为不同的类型(门将、技术和心理)。同样,这只是解决问题,但这可以帮助你集中注意力。

#5


0  

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.)

另一种可能是覆盖属性的默认getter。在getter中,您可以查看这些值是否已初始化,如果未初始化,则返回默认值。(这对某些属性类型有效,但对其他类型无效——显然,您需要默认值是表示没有设置值的值。)

#6


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

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.

如果对象是视图,可以在commonInit函数中设置默认值并执行默认逻辑。如果不是视图,你可以在init函数中实现。

#7


0  

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

是的,您可以重写getter,以防在属性输入之前设置默认值。

For example, define property in .h file:

例如,在.h文件中定义属性:

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

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

并在.m文件中覆盖getter和设置默认值:

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