【问题标题】:static NSDictionary* const letterValues = @{ ..... } in a method does not compile方法中的静态 NSDictionary* const letterValues = @{ ..... } 无法编译
【发布时间】:2014-04-27 08:58:08
【问题描述】:

a word game for iPhone:

我正在尝试在我的自定义视图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];
}

不幸的是,这给了我编译错误Initializer element is not a compile-time constant,我必须删除 static 关键字才能在 Xcode 中编译我的应用程序(此处为 fullscreen):

我想我正确地初始化了NSDictionary - 使用新的Objective-C Literals 语法。

但是为什么我不能在这里使用static

我认为在这里确保我的letterValues 常量只设置一次是合适的吗?

【问题讨论】:

  • 把它移出课堂
  • 将其从类中移出会导致相同的编译时错误
  • @Btw.,该代码是有效的并且在Objective-C++中工作:-)
  • 哪个代码有效(我的问题中的代码在 Xcode 5.1 中无法编译)以及 Objective-C++ 是什么意思?
  • @AlexanderFarber:请参阅stackoverflow.com/questions/3684112/what-is-objective-c - Objective-C++ 是 Objective-C 与 C++ 的“组合”(并且文档很少)。 Objective-C++ 文件的扩展名为 .mm。如果您将文件重命名为“Tile.mm”,您的代码应该可以编译,因为 C++ 对静态初始化程序有不同的规则。 - 但这只是作为一个评论,而不是作为 the 解决方案。 - 你也可以看看stackoverflow.com/questions/21365532/…,这是一个不同的问题,有相似的答案。

标签: ios objective-c static nsdictionary constants


【解决方案1】:

您只能在初始化期间使用常量设置静态变量。 @{} 创建一个对象,因此不是常量。

改为这样做:

- (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 实现了所需的锁定。

【讨论】:

  • 使用dispatch_once 是初始化此类数据对象的最佳和最安全的方法。这是这里最正确的答案。
【解决方案2】:

您可以使用静态,但不能在同一行进行赋值。试试这个:

- (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:]),在编译时无法解析。

【讨论】:

    【解决方案3】:

    另一种选择是使用宏方法:

    宏观(最简单)方法(2021 年)

    #define kScreenNames @{ \
            @"HOME":                     @"Home Page", \
            @"SEARCH":                   @"Search Page", \
            @"MYLISTS":                  @"My List", \
            @"MYACCOUNT":                @"My Aaccount" \
    }
    

    它简短而优雅。

    然后,您可以像使用任何其他 NSDictionary 一样使用它。

    我希望这会帮助地球上的某个人。

    最好的

    【讨论】:

      【解决方案4】:

      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 子类中多次调用您的代码。

      【讨论】:

      • + (void)load 会不会更合适?
      • @dwery 这真的取决于你的用例。请参阅this question 以了解有关loadinitialize 之间区别的更多信息。
      【解决方案5】:

      如果您支持 iOS 14(及其与年份一致的版本)或更高版本,您现在可以执行此操作,假设您的密钥为 NSStrings。这是因为Xcode 13 supports Clang 的-fobjc-constant-literals 标志,默认开启。

      【讨论】:

        猜你喜欢
        • 2011-04-28
        • 2016-06-18
        • 2010-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-15
        • 2019-05-03
        相关资源
        最近更新 更多