2009-06-29 5 views
2

Ein View-Controller FooViewController muss einige Initialisierungen durchführen, wenn er erstellt wird (an sich, nicht in der verwalteten Ansicht - bevor die Ansicht überhaupt geladen wird).Ein View-Controller, der sowohl programmatisch als auch in IB instanziiert werden kann?

Ich will es schaffen auf zwei Arten zu:

  1. Programatically, möglicherweise mit einigen Argumenten:

     
    FooViewController *fooViewController = [[[FooViewController alloc] initWithSomeData:data] autorelease]; 
    [self.navigationController pushViewController:fooViewController animated:YES]; 
    
  2. In Interface Builder.

Für (1) Ich würde die initializers so schreiben:

 
- (id)initWithSomeData:(Data *)data  // designated initializer 
{ 
    if (self = [super initWithNibName:@"FooView" bundle:nil]) { 
     self.title = "Foo"; 
     // perform initialization 
    } 
    return self; 
} 
- (id)init 
{ 
    return [self initWithSomeData:nilOrSomeDefaultValue]; 
} 

// ... other initializers that call the designated initializer 

(I codieren die Spitze Name, da der Controller immer die gleiche Ansicht Konfiguration verwendet, und weil welcher Ansicht er verwendet nicht funktioniert betreffen die Anrufer überhaupt)

Wenn in Interface Builder erstellt, würde ich wollen, dass das Endergebnis das selbe ist, als wenn das Objekt mit dem parameterless init initialisiert wurde.

Nun, wenn ich nur:

 
- (id)initWithCoder:(NSCoder *)decoder 
{ 
    return [self init]; 
} 

Die title, wantsFullScreenLayout und nibName Eigenschaften, die im Inspector im Interface Builder eingestellt werden, würde dann ignoriert werden, aber das ist OK. Der NibName ist in init fest codiert und title wird dort gesetzt, falls der Controller sowieso programmgesteuert instanziiert wird.

Das Problem ist, dass parentViewController nicht festgelegt ist (der Standardwert initWithCoder: würde es basierend auf der Hierarchie der Objekte in der NIB festlegen).

Wie kann ich das übergeordnete Objekt von der Spitze bekommen? Ich würde dann initWithCoder: wie etwas ändern:

 
- (id)initWithCoder:(NSCoder *)decoder 
{ 
    if (self = [self init]) { 
     _parentViewController = [decoder parentObject]; 
    } 
    return self; 
} 

Oder sollte ich etwas anderen Ansatz verwenden Controller zu schaffen, die sowohl programmatisch und in IB instanziiert werden kann?

Antwort

0

Versuchen Sie nicht, einen Viewcontroller zu erstellen, der mit und ohne Feder funktioniert. Es wird ein Albtraum sein, da das nibloading einige der normalen Einstiegspunkte verwendet und neue bereitstellt, und es wird in Bezug auf OS-Revisionen fragil sein.

Was Sie tun können, ist es die View-Controller immer von einer Feder laden machen, dann geben Sie sich eine Bequemlichkeit initializer durch die Spitze zu gehen:

- (id) init { 
    return [[[self class] alloc] initWithNibNamed:@"MyNibName" bundle:nil]; 
} 

Dann Sie es durch andere nibs die normale Art und Weise referenzieren , und rufen Sie einfach die Convenience-Init-Methode auf, wenn Sie nicht explizit mit der Nib arbeiten möchten.

+0

Ist '[Selbstklasse]' angeblich nur 'selbst'? Wenn ja, laden Sie den View-Controller nicht wirklich von NIB. Die nibName-Eigenschaft von UIViewController ist die NIB für die Ansicht, nicht der Controller selbst. Ich glaube nicht, zwei NIBs für jeden Controller (eine für sich selbst, eine für die Ansicht) ist der Weg zu gehen ...:/ –

+0

Es ist behoben, es soll sein [[Selbstklasse] Alloc) da ich nicht weiß, was deine Klasse ist. Um das zu tun, was ich vorgeschlagen habe, müssen Sie den Eigentümer der Datei auf Ihre Klasse einstellen. Was initWithNibNamed tut, ist, dass es den View-Controller initialisiert und dann alle Verbindungen mit der Nib in die VC bindet, die Sie gerade initialisiert haben. Es sieht so aus, als ob du versuchst, ein separates View-Controller-Objekt in der Nib zu erstellen. Wie stellst du deinen File-Besitzer ein? Ich glaube, du kämpfst gegen das System. –

+0

Ahh, ich glaube, du hast die Frage falsch verstanden ... Der View-Controller wird * immer * eine Feder für die eigene Sicht benutzen. Ich baue immer Ansichten in IB. Der Unterschied besteht darin, ob * das Objekt controller * programmatisch oder in einer Nib erstellt wird. –

0

Warum nicht init stuff in viewDidLoad - Wenn Sie außerhalb von IB erstellen, können Sie initiale Werte mit einigen anderen Methoden oder Eigenschaften nach der Initialisierung setzen, aber bevor viewDidLoad aufgerufen wird.

+1

Weil viewDidLoad für die Ansichtsinitialisierung gedacht ist, nicht für die Controller-Initialisierung. Zum Beispiel kann es in Situationen mit wenig Speicher aufgerufen werden, wenn die Ansicht freigegeben ist. Die Controller-Initialisierung sollte natürlich in init erfolgen. –

+0

Oder überprüfen Sie, ob die Initialisierung bereits durchgeführt wurde, bevor Sie es erneut in ViewDidLoad tun. Da Sie in in IB instanziierten View-Controllern natürlich keine benutzerdefinierten Parameter an init übergeben können, benötigen Sie einen Platz, der sowohl bei der IB-Initialisierung als auch bei der Standarderstellung aufgerufen wird, mit der Möglichkeit, Parameter zu übergeben (entsprechend der ursprünglichen Frage). . viewDidLoad ist ein guter Kandidat dafür, da Sie auch die Ansicht-spezifische Initialisierung durchführen werden. Ansonsten haben Sie verschiedene Init-Methoden, mit denen Sie sich verwirren können. –

+0

Außerdem können Sie mit viewDidLoad einen View-Controller initialisieren, einige Parameter jedoch über Eigenschaften festlegen, bevor die Ansicht tatsächlich geladen wird. –

Verwandte Themen