2009-03-08 9 views
4

I nicht planen, um Anwendungen ohne IB zu schreiben, bin ich gerade dabei, mehr über Programmierung zu lernen.Cocoa ohne Interface Builder, eine Instanz von App-Controller initialisieren?

Wie kann ich eine einzelne Instanz meiner AppController-Klasse beim Start erhalten? (Es wird normalerweise von der Feder geladen.) Und können Sie die Verwendung von +initialize und -init aufräumen? Wenn ich das verstehe, wird beim Start +initialize für alle Klassen aufgerufen. Wie kann ich damit eine Instanz meines AppControllers mit Instanzvariablen erstellen, aus denen meine Schnittstelle besteht?

Hoffen Sie, dass das Sinn macht, und danke für jede Hilfe.

Antwort

7

+initalize wird zum ersten Mal an eine Klasse gesendet, wenn sie oder eine ihrer Unterklassen zum ersten Mal eine Nachricht empfängt. Also, wenn Sie das tun:

instance = [[[YourClass alloc] init] autorelease]; 

Die alloc Nachricht initialize auslöst.

Wenn Sie das Gleiche mit einer Unterklasse zu tun:

instance = [[[SubclassOfYourClass alloc] init] autorelease]; 

Die alloc Nachricht auslösen +[YourClass initialize] die gleiche Art und Weise hat die anderen (vor dem Auslösen auch +[SubclassOfYourClass initialize] Aber nur einer von ihnen wird it- tun. jede initialize Klasse wird nie mehr als einmal aufgerufen. (es sei denn, Sie es selbst nennen mit [super initialize] oder [SomeClass initialize] -so das nicht tun, weil die Methode es nicht erwartet wird.)

-init, auf der anderen Seite, initialisiert eine neue Instanz Im Ausdruck [[YourClass alloc] init] senden Sie die Nachricht persönlich direkt an die Instanz. Sie können es auch indirekt über einen anderen Initialisierer ([[YourClass alloc] initWithSomethingElse:bar]) oder eine Convenience Factory ([YourClass instance]) aufrufen.

Im Gegensatz zu initialize sollten Sie immer init (oder einen anderen Initialisierer, falls zutreffend) an Ihre Oberklasse senden. Die meisten init Methoden aussehen grob wie folgt aus:

- (id) init { 
    if ((self = [super init])) { 
     framistan = [[Framistan alloc] init]; 
    } 
    return self; 
} 

Details unterscheiden (diese Methode oder die Superklasse oder beide Argumente annehmen kann, und einige Leute bevorzugen self = [super init] auf seine eigene Linie und Wil Shipley doesn't assign to self at all), aber die Grundidee ist die gleiche : Rufen Sie [super init[WithSomething:…]], stellen Sie sicher, dass es nil nicht zurückgegeben hat, richten Sie die Instanz ein, wenn dies nicht der Fall ist, und geben Sie zurück, was auch immer die Oberklasse zurückgegeben hat.

Dies bedeutet, dass Sienil von init zurückkehren können, und in der Tat können Sie. Wenn Sie dies tun, sollten Sie [self release], damit Sie das fehlerhafte Objekt nicht verlieren. (Für ungültige Argumentwerte zu erfassen, ist eine Alternative NSParameterAssert, die eine Ausnahme auslöst, wenn die Behauptung fehlschlägt. Die relativen Vorzüge sind jeweils über den Rahmen dieser Frage.)

Wie kann ich diese verwenden, um eine Instanz zu erstellen von meinem AppController mit Instanzvariablen, die meine Schnittstelle ausmachen?

Der beste Weg ist es alles in main zu tun:

int main(int argc, char **argv) { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    AppController *controller = [[[AppController alloc] init] autorelease]; 
    [[NSApplication sharedApplication] setDelegate:controller]; //Assuming you want it as your app delegate, which is likely 
    int status = NSApplicationMain(argc, argv); 

    [pool drain]; 
    return status; 
} 

Sie werden in Ihrer Anwendung in AppController Delegatmethoden anderes Set-up tun.

Das wissen Sie bereits, aber für jeden, der dies liest: Nibs sind dein Freund. Interface Builder ist dein Freund. Kämpfen Sie nicht mit der Framework-Arbeit und bauen Sie Ihre Schnittstelle grafisch auf, und Ihre Anwendung wird dafür besser sein.

+1

Danke eine Tonne, das hat geholfen, aber es sieht aus wie IB ziemlich viel tut. Ich habe eine Methode in AppController namens load interface erstellt und in main aufgerufen. AppController * Controller = [...] [Controller LoadInterface]; Wenn ich versuche, einen Wert zu meinem Controller Variable Hauptfenster zuweisen, (continue Kommentar) ... – cemulate

+0

erhalte ich Konsole Fehler: _NXCreateWindow: Fehler Einstellungsfenster Eigenschaft (1002) _NSSetWindowTag, Fehler Clearing Fenster Tags (1002) _NSSetWindowTag , Fehlereinstellung Fenster-Tags (1002) Kann dies behoben werden? – cemulate

+0

Sie müssen NSApplication ausführen, bevor Sie Fenster erstellen können. Deshalb ist es besser, Ihren Controller zum Anwendungsdelegaten zu machen und Fenster in Ihren Delegiertenmethoden zu erstellen/zu laden. (Beachten Sie, dass Befehlszeilen-Apps * keine * Fenster erstellen können, weil sie NSApplication noch nicht ausgeführt haben und dies auch nie tun werden.) –

1

Eine Reihe von NIBs scheinen eine unbefriedigende Antwort zu sein, auch wenn sie in XML (als XIB) dargestellt werden, weil es keine einfache Möglichkeit gibt, sie mit einem Standard-Subversions- oder SCM-Stil-Tool zu vergleichen oder zu verbinden. Die codierte Information ist zerbrechlich und nicht dazu bestimmt, von bloßen Menschen bearbeitet zu werden. Wie würden Änderungen durch eine GUI dargestellt? Würde ich jedes Attribut jeder Kontrolle durchlaufen und sie visuell überprüfen?

Wenn das Verhalten der App in Code geschrieben ist, gibt es eine Chance, dass ich herausfinden kann, was passiert, auch wenn ich viele Details gleichzeitig zur Hand haben muss.

Eine vorgeschlagene Lösung: Verwenden Sie eine Top-Level-NIB, die der Hauptarchitekt codiert, aber dann den Rest der App explizit codieren.

Hat jemand eine bessere Idee?

1

Eine weitere Lösung für das Problem, eine App ohne Feder zu starten.

Statt eine eigene Controller von allocing, verwenden Sie nur die zusätzlichen Parameter in der NSApplicationMain() Methode:

int retVal = NSApplicationMain(argc, argv, @"UIApplication", @"MyAppDelegate"); 

Diese kümmert sich um alle die richtige Verknüpfung man braucht.

Dann müssen Sie nur noch daran denken, ein eigenes Fenster zu erstellen und es sichtbar zu machen.

+0

Antwort auf greggT. Mach einfach das, was ich oben gesagt habe! Löschen Sie alle XIB-Dateien vom Anfang Ihres Projekts, gehen Sie in main.m und fügen Sie dann die beiden Parameter, die ich oben erwähnt habe, zu Ihren NSApplicationMain() - Argumenten hinzu. Sie würden dann in Ihr AppDelegate gehen und Ihr eigenes Fenster spawnen (da kein XIB verwendet wird) und Ihrem View die Ansicht Ihres Nicht-XIB ViewControllers oder NavControllers hinzufügen. mache es keyandvisible und du hast ein ganzes Projekt ohne XIBs erstellt, das funktioniert genau so, wie die ursprünglich angegebenen XIBs beabsichtigen. –

+0

Bearbeiten Sie auch Ihre Informationen.Klicken Sie auf Hinzufügen, um den Namen der .xib-Datei aus den Projekteinstellungen zu löschen –

Verwandte Themen