问题
In a word game for iPhone:
I'm trying to use the following code in my custom view Tile.m:
- (void)awakeFromNib
{
[super awakeFromNib];
static NSDictionary* const letterValues = @{
@"A": @1,
@"B": @4,
@"C": @4,
// ...
@"X": @8,
@"Y": @3,
@"Z": @10,
};
NSString* randomLetter = [kLetters substringWithRange:[kLetters rangeOfComposedCharacterSequenceAtIndex:arc4random_uniform(kLetters.length)]];
int letterValue = [letterValues[randomLetter] integerValue];
_smallLetter.text = _bigLetter.text = randomLetter;
_smallValue.text = _bigValue.text = [NSString stringWithFormat:@"%d", letterValue];
}
Unfortunately this gives me compile error Initializer element is not a compile-time constant and I have to remove the static keyword to get my app compile in Xcode (here fullscreen):
I think I initialize the NSDictionary correctly - by using the new Objective-C Literals syntax.
But why can't I use static here?
I thought it would be appropriate here to make sure that my letterValues constant is set only once?
回答1:
You can only set a static variable during initialization with a constant. @{} creates an object, thus not a constant.
Do this instead:
- (void)awakeFromNib
{
[super awakeFromNib];
static NSDictionary* letterValues = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
letterValues = @{
@"A": @1,
@"B": @4,
@"C": @4,
// ...
@"X": @8,
@"Y": @3,
@"Z": @10,
};
});
...
}
Some other answers here suggest a check for nil instead of dispatch once, but that can cause issues when creating multiple tiles at the same time (via threads). dispatch_once implements the required locking.
回答2:
You can use static, but the assignment can't be made on the same line. Try this:
- (void)awakeFromNib {
[super awakeFromNib];
static NSDictionary* letterValues = nil;
if (!letterValues) {
letterValues = @{@"A": @1,
@"B": @4,
@"C": @4,
// ...
@"X": @8,
@"Y": @3,
@"Z": @10};
}
...
}
The reason is that the @{<key> : <value>} syntax is translated by the compiler into an Objective-C method ([[NSPlaceholderDictionary alloc] initWithObjects:forKeys:count:]), which cannot be resolved at compile-time.
回答3:
NSDictionary objects can't be created at compile time. However, if you need a static object, you can create one. You can, for example, use the initialize method, like this:
static NSDictionary* letterValues;
+ (void)initialize
{
if (self == [MyClass class]) {
letterValues = @{
@"A": @1,
@"B": @4,
@"C": @4,
@"X": @8,
@"Y": @3,
@"Z": @10,
};
}
}
The if statement is there to prevent multiple calls of your code in MyClass subclasses.
来源:https://stackoverflow.com/questions/22534251/static-nsdictionary-const-lettervalues-in-a-method-does-not-compil