Compilerfehler: "Initialisiererelement ist keine Kompilierungszeitkonstante"

76

Beim Kompilieren dieses Codes wird der Fehler "Initialisierungselement ist keine Konstante zur Kompilierungszeit" angezeigt. Kann jemand erklären warum?

#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
Nick
quelle

Antworten:

105

Wenn Sie eine Variable außerhalb des Funktionsumfangs definieren, wird der Wert dieser Variablen tatsächlich in Ihre ausführbare Datei geschrieben. Dies bedeutet, dass Sie nur einen konstanten Wert verwenden können. Da Sie zur Kompilierungszeit nicht alles über die Laufzeitumgebung wissen (welche Klassen verfügbar sind, wie ihre Struktur ist usw.), können Sie erst zur Laufzeit objektive c-Objekte erstellen, mit Ausnahme von konstanten Zeichenfolgen, denen eine bestimmte gegeben ist Struktur und garantiert so zu bleiben. Sie sollten die Variable auf Null initialisieren und +initializezum Erstellen Ihres Bildes verwenden. initializeist eine Klassenmethode, die aufgerufen wird, bevor eine andere Methode für Ihre Klasse aufgerufen wird.

Beispiel:

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;
}
ughoavgfhw
quelle
4
Eine andere Möglichkeit besteht darin, eine Funktion mit zu verwenden __attribute__ ((constructor)).
12
Eine weitere Option besteht darin, den Typ Ihrer Quelldatei von Objective-C auf Objective-C ++ zu ändern (oder ihn von .m in .mm umzubenennen, was den gleichen Effekt hat). In C ++ müssen solche Initialisierer keine konstanten Werte zur Kompilierungszeit sein, und der ursprüngliche Code würde einwandfrei funktionieren.
Imre
1
Gibt es eine Möglichkeit, eine constsolche zu deklarieren ? Dh eine Variable, die nur einmal und nie wieder gesetzt werden kann?
Devios1
Was ist, wenn ich eine Konstante aus mehreren Dateien einfügen möchte? Ist es möglich, die Initialisierungsfunktion mehrmals zu schreiben, d. H. Kann es aus mehreren Teilen bestehen?
Vladimir Despotovic
@VladimirDespotovic Nein, es kann nicht geteilt werden. Sie können eine +initializeMethode für verschiedene Klassen haben oder Funktionen aus anderen Dateien aufrufen, aber Sie müssen mit solchen Dingen wirklich vorsichtig sein. Es ist wirklich am besten, wenn möglich zu vermeiden.
ughoavgfhw
23

Eine globale Variable muss mit einem konstanten Wert wie 4oder 0.0oder @"constant string"oder initialisiert werden nil. Ein Objektkonstruktor wie beispielsweise initgibt keinen konstanten Wert zurück.

Wenn Sie eine globale Variable haben möchten, sollten Sie sie initialisieren nilund dann mit einer Klassenmethode zurückgeben:

NSImage *segment = nil;

+ (NSImage *)imageSegment
{
    if (segment == nil) segment = [[NSImage alloc] initWithContentsOfFile:@"/user/asd.jpg"];
    return segment;
}
Mipadi
quelle
Warum könnten Sie statisches NSString haben - mit der Syntax @ "myString", wenn NSString ein Objekt ist?
Paul Brewczynski
4
@bluesm: Der Objective-C-Compiler verwendet einige Tricks, um eine Zeichenfolge zu erstellen, die als konstanter Wert behandelt wird.
Mipadi
11

Weil Sie den Compiler bitten, eine statische Variable mit Code zu initialisieren, der von Natur aus dynamisch ist.

bbum
quelle
6

Der Grund ist, dass Sie Ihre imageSegmentFunktion außerhalb einer Funktion in Ihrem Quellcode definieren (statische Variable).

In solchen Fällen kann die Initialisierung nicht die Ausführung von Code umfassen, z. B. das Aufrufen einer Funktion oder das Zuweisen einer Klasse. Der Initialisierer muss eine Konstante sein, deren Wert zur Kompilierungszeit bekannt ist.

Sie können dann Ihre statische Variable innerhalb Ihrer initMethode initialisieren (wenn Sie die Deklaration auf init verschieben).

Sergio
quelle
1
Statische Speicherklasse ist das Problem. Das Problem würde auch dann auftreten, wenn es sich innerhalb einer Funktion befindet (und als statisch deklariert ist).
JWW
@noloader: Ich habe nie das Gegenteil gesagt ... :-) Nur der spezielle Fall der statischen Speicherung im Fall des OP war eine globale Variable ... (in Klammern das Konzept - alles hängt davon ab, wer der Leser ist, ob Es ist besser, mit dem Konzept oder dem konkreten Fall zu beginnen.
Sergio
4

Sie können ein Makro wie folgt definieren. Der Compiler ersetzt "IMAGE_SEGMENT" vor dem Kompilieren durch seinen Wert. Sie können zwar eine globale Suche für Ihr Array definieren, diese ist jedoch nicht mit einer globalen Variablen identisch. Wenn das Makro erweitert wird, funktioniert es genau wie Inline-Code, sodass jedes Mal ein neues Bild erstellt wird. Wenn Sie also vorsichtig sind, wo Sie das Makro verwenden, hätten Sie effektiv eine globale Variable erstellt.

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

Verwenden Sie es dann dort, wo Sie es benötigen, wie unten gezeigt. Jedes Mal, wenn der folgende Code ausgeführt wird, wird ein neues Objekt mit einem neuen Speicherzeiger erstellt.

imageSegment = IMAGE_SEGMENT
Kris Subramanian
quelle