static NSDictionary* const letterValues = @{ … } in a method does not compile

橙三吉。 提交于 2019-12-04 09:13:05

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!