web-dev-qa-db-ja.com

コンパイラエラー:「初期化子要素はコンパイル時定数ではありません」

このコードをコンパイルすると、「初期化子要素はコンパイル時定数ではありません」というエラーが表示されます。誰でもその理由を説明できますか?

#import "PreferencesController.h"

@implementation PreferencesController

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
    }

    return self;
}


NSImage* imageSegment = [[NSImage alloc] initWithContentsOfFile:@"/User/asd.jpg"];//error here
73
Nick

関数のスコープ外で変数を定義すると、その変数の値は実際に実行可能ファイルに書き込まれます。これは、定数値のみを使用できることを意味します。コンパイル時のランタイム環境に関するすべて(使用可能なクラス、その構造など)がわからないため、特定の文字列が指定されている場合を除き、ランタイムまでにObjective Cオブジェクトを作成することはできません。構造とその方法にとどまることが保証されています。行うべきことは、変数をnilに初期化し、+initializeを使用してイメージを作成することです。 initializeは、クラスで他のメソッドが呼び出される前に呼び出されるクラスメソッドです。

例:

NSImage *imageSegment = nil;
+ (void)initialize {
    if(!imageSegment)
        imageSegment = [[NSImage alloc] initWithContentsOfFile:@"/User/asd.jpg"];
}
- (id)init {
    self = [super init];
    if (self) {
        // Initialization code here.
    }

    return self;
}
102
ughoavgfhw

グローバル変数は、4または0.0または@"constant string"またはnilなどの定数値に初期化する必要があります。 initなどのオブジェクトコンストラクターは、定数値を返しません。

グローバル変数が必要な場合は、nilに初期化してからクラスメソッドを使用して返す必要があります。

NSImage *segment = nil;

+ (NSImage *)imageSegment
{
    if (segment == nil) segment = [[NSImage alloc] initWithContentsOfFile:@"/user/asd.jpg"];
    return segment;
}
21
mipadi

本質的に動的なコードで静的変数を初期化するようコンパイラーに要求しているからです。

10
bbum

理由は、ソースコード(静的変数)の関数の外側でimageSegmentを定義しているためです。

そのような場合、関数の呼び出しやクラスの割り当てなど、コードの実行を初期化に含めることはできません。初期化子は、コンパイル時に値がわかっている定数でなければなりません。

その後、initメソッド内で静的変数を初期化できます(その宣言をinitに延期する場合)。

5
sergio

以下に示すように、マクロを確実に#defineできます。コンパイラは、コンパイルの前に「IMAGE_SEGMENT」をその値に置き換えます。配列のグローバルルックアップを定義することはできますが、グローバル変数とは異なります。マクロを展開すると、インラインコードのように機能するため、毎回新しいイメージが作成されます。したがって、マクロの使用場所に注意すれば、グローバル変数の作成を効果的に達成できたでしょう。

#define IMAGE_SEGMENT [[NSImage alloc] initWithContentsOfFile:@"/User/asd.jpg"];

次に、以下に示すように、必要な場所で使用します。以下のコードが実行されるたびに、新しいオブジェクトが新しいメモリポインターで作成されます。

imageSegment = IMAGE_SEGMENT
3