web-dev-qa-db-ja.com

static NSDictionary * const letterValues = @ {.....}メソッド内でコンパイルされません

iPhone用のWordゲーム

app screenshot

カスタムビューで次のコードを使用しようとしています 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];
}

残念ながら、これによりコンパイルエラーが発生します初期化要素はコンパイル時の定数ではありません。アプリを取得するにはstaticキーワードを削除する必要がありますXcodeでコンパイル(ここでは fullscreen ):

Xcode screenshot

新しい Objective-C Literals 構文を使用して、NSDictionaryを正しく初期化すると思います。

しかし、ここでstaticを使用できないのはなぜですか?

私のletterValues定数が1度だけ設定されることを確認することは、ここでは適切だと思いましたか?

13

静的変数は、初期化中に定数でのみ設定できます。 @ {}はオブジェクトを作成するため、定数ではありません。

代わりにこれを行ってください:

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


    ...
}

ここでの他のいくつかの回答は、一度ディスパッチするのではなくnilのチェックを提案していますが、これは複数のタイルを同時に(スレッドを介して)作成するときに問題を引き起こす可能性があります。 dispatch_onceは必要なロックを実装します。

42
Dave Wood

静的を使用できますが、同じ行で割り当てを行うことはできません。これを試して:

- (void)awakeFromNib {
    [super awakeFromNib];

    static NSDictionary* letterValues = nil;
    if (!letterValues) {
        letterValues = @{@"A": @1,
                         @"B": @4,
                         @"C": @4,
                         // ...
                         @"X": @8,
                         @"Y": @3,
                         @"Z": @10};
    }
    ...
}

その理由は、@{<key> : <value>}構文は、コンパイラーによってObjective-Cメソッド([[NSPlaceholderDictionary alloc] initWithObjects:forKeys:count:])、コンパイル時に解決できません。

5
Austin

NSDictionaryオブジェクトはコンパイル時に作成できません。ただし、静的オブジェクトが必要な場合は作成できます。たとえば、次のようにinitializeメソッドを使用できます。

static NSDictionary* letterValues;

+ (void)initialize
{
    if (self == [MyClass class]) {
        letterValues = @{
                         @"A": @1,
                         @"B": @4,
                         @"C": @4,
                         @"X": @8,
                         @"Y": @3,
                         @"Z": @10,
                         };
    }
}

Ifステートメントは、MyClassサブクラスでのコードの複数呼び出しを防ぐためにあります。

1
Adam