UIView und initWithFrame sowie eine NIB-Datei. Wie kann ich die NIB-Datei laden?

76

Ich habe einen UIViewAnruf baseViewund darin habe ich, initWithFramewo ich einige andere Ansichten hinzufüge und einige benutzerdefinierte Sachen mache. Dieselbe Ansicht enthält auch eine NIB-Datei.

Jetzt habe ich eine UIViewControllerKlasse mit dem Namen, AppControllerin der ich die baseViewAnsicht zur Ansicht der AppControllerAnsicht hinzufügen möchte, also mache ich das:

self.view = baseView;Das Problem ist jedoch, dass die NIB-Datei nicht geladen wird. Wie stelle ich sicher, dass das angepasste Material UND die NIB-Datei geladen / ausgeführt werden?

dbrasco
quelle

Antworten:

168

Sie haben viele Optionen, je nachdem, wie Ihre "baseView" -Klasse verwendet und in Ihre Anwendung integriert werden soll. Es ist nicht klar, wie Sie diese Klasse verwenden möchten - als Ansicht in einer UIViewController-Unterklasse oder als wiederverwendbare modulare Komponente, die in Ihrer gesamten Anwendung mehrfach instanziiert werden soll, um in vielen verschiedenen Ansichtscontrollern verwendet zu werden.

Wenn Ihre Ansicht die einzige Ansicht in einer UIViewController-Unterklasse sein soll, ist Phonitive korrekt. Bündeln Sie sie zusammen mit der .xib-Datei der UIViewController-Unterklasse und verwenden Sie die viewDidLoad des UIViewController, um die endgültige Initialisierung durchzuführen.

Wenn Sie jedoch möchten, dass Ihre View-Klasse eine Unterkomponente ist, die mehrfach in verschiedenen View-Controllern wiederverwendet wird und entweder über Code oder durch Aufnahme in eine .xib-Datei für einen anderen Controller integriert wird, müssen Sie sowohl die initWithFrame: init-Methode als auch awakeFromNib implementieren. beide Fälle zu behandeln. Wenn Ihre interne Initialisierung immer einige Objekte aus .xib enthält, müssen Sie Ihre .xib in Ihrem initWithFrame manuell laden, um "Kunden" -Klassen zu unterstützen, die Ihr Widget über Code erstellen möchten. Wenn eine .xib-Datei Ihr Objekt enthält, müssen Sie sicherstellen, dass Sie alle für den Code erforderlichen Finalisierungen von awakeFromNib aus aufrufen.

Hier ist ein Beispiel für das Erstellen einer UIView-Unterklassenkomponente mit dem UI-Design in einer Schreibfeder.

MyView.h:

@interface MyView : UIView
{
    UIView *view;
    UILabel *l;
}
@property (nonatomic, retain) IBOutlet UIView *view;
@property (nonatomic, retain) IBOutlet UILabel *l;

MyView.m:

#import "MyView.h"
@implementation MyView
@synthesize l, view;

- (id)initWithFrame:(CGRect)frame 
{
    self = [super initWithFrame:frame];
    if (self) 
    {
        // Initialization code.
        //
        [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
        [self addSubview:self.view];
    }
    return self;
}

- (void) awakeFromNib
{
    [super awakeFromNib];

    // commenters report the next line causes infinite recursion, so removing it
    // [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
    [self addSubview:self.view];
}

- (void) dealloc
{
     [l release];
     [view release];
     [super dealloc];
}

So sieht die NIB-Datei aus (außer dass der Eigentümer dieser Datei in die MyView-Klasse geändert werden muss).

Geben Sie hier die Bildbeschreibung ein

Stellen Sie sicher, dass sowohl die Ansichts- als auch die Beschriftungsausgänge mit dem Eigentümer der Datei verbunden sind. Das ist es! Eine Vorlage zum Erstellen wiederverwendbarer UIView-Widgets.

Das wirklich Schöne an dieser Struktur ist, dass Sie Instanzen Ihres MyView-Objekts in anderen NIB-Dateien platzieren können, einfach eine UIView an der gewünschten Position / Größe platzieren und dann die Klasse im Identitätsinspektor (CMD-4) in MyView ändern können. und boom, du hast eine Instanz deines Widgets in jeder gewünschten Ansicht! Genau wie bei UIKit-Objekten können Sie Delegierungsprotokolle implementieren, damit Objekte, die Ihr Widget verwenden, über interessante Ereignisse informiert werden und Daten bereitstellen können, die im Widget angezeigt werden, um es anzupassen.

Bogatyr
quelle
1
Normalerweise möchte ich beim Erstellen einer App einige Ansichten erstellen und diese Ansichten in einem View Controller verwenden. Ich möchte nicht für jede Ansicht einen Ansichts-Controller erstellen. Deshalb erstelle ich separate Ansichten, die ich in die Ansicht eines Ansichts-Controllers aufnehmen möchte.
Dbrasco
2
Ich mag die Tatsache, dass Sie sagen, ich kann initWithFrame und awakeFromNib implementieren, aber ich bin nicht sicher, welche Art von Initialisierung ich in welcher Reihenfolge vornehmen muss. Könnten Sie ein Beispiel geben? Angenommen, ich habe mit IB einige Beschriftungen und Schaltflächen im XIB hinzugefügt. Ich habe einige IBOutlets in meiner Ansicht. Jetzt möchte ich in initWithFrame etwas mit diesen Objekten machen. Wie würde ich die Ansicht mit der NIB initiieren, damit sie über diese Objekte Bescheid weiß?
Dbrasco
2
Tatsächlich. Zugegeben, es gibt mehrere Fälle, in denen ich einfach eine andere VC + -Ansicht auf den Navigationscontroller übertragen kann, aber das ist nicht immer der Fall. Jetzt muss ich noch einmal über IBPlugins lesen, zum Beispiel: cocoawithlove.com/2009/07/… (warte, nein, nicht iOS-spezifisch, aber immer noch ...)
Joe D'Andrea
5
loadNibNamed inside awakeFromNib verursacht endlose Rekursion
Gargo
1
Es ist wahr, @Gargo ist korrekt, ich habe gerade diesen Code getestet (großartige Antwort), aber ich habe bei der Initialisierung eine Endlosschleife eingegeben, nachdem das loadNibNamed in awaleFromNib entfernt wurde, hat dieses Problem aufgehört. Vielen Dank.
Ospho
3

Ich habe diesen Beitrag gefunden, nachdem ich in meiner App ein Problem damit hatte. Ich habe versucht, die Ansicht von einer NIB in der ViewDidLoad-Methode zu instanziieren, aber die Steuerelemente haben sich so verhalten, als wären sie deaktiviert. Ich hatte Probleme damit, die userInteractionEnabled-Eigenschaft direkt festzulegen und den Touch-Ereignis-Selektor für eine Schaltfläche in dieser Ansicht programmgesteuert festzulegen. Nichts hat geklappt. Ich bin auf einen anderen Beitrag gestoßen und habe festgestellt, dass viewDidLoad wahrscheinlich zu früh war, um diese NIB zu laden. Ich habe die Last auf die ViewWillAppear-Methode verschoben und alles hat funktioniert. Hoffe, das hilft jemand anderem, der damit zu kämpfen hat. Die Hauptantwort war großartig und funktioniert jetzt gut für mich, da ich sie vom richtigen Ort aus anrufen lasse.

Crissag
quelle
1
Bitte teilen Sie uns den Link zu diesem anderen Beitrag mit.
Er erwähnt wahrscheinlich stackoverflow.com/a/819265/779419 . Stellen Sie beim Instanziieren der benutzerdefinierten Ansicht sicher, dass initWithFrame tatsächlich mit einem geeigneten CGRect verwendet wird.
schieferstapel
2

Wenn Sie eine NIB verwenden möchten, ist es besser, wenn Ihr UIView mit einem UIViewController verknüpft ist. In diesem Fall können Sie es verwenden

UIViewController *vc=[[UIViewController alloc] initWithNibName:@"YourNIBWihtOUTEXTENSION" bundle:nil]

[self.view addSubView:vc.view ];

Aufgrund von Speicherlecks müssen Sie vc freigeben

Phonitiv
quelle
Nicht wahr; Wenn Sie den Inhalt eines UIView mit dem Interface Builder ändern müssen, müssen Sie die Bogatyr-Methode verwenden. Der Grund, warum Sie UIView in Verbindung mit Nib verwenden müssten, ist, dass Apple von der Verwendung der Verschachtelung von UIViewControllern abrät, da übergeordnete Aufrufe unterbrochen werden können. Das ist, wenn Sie <iOS 5 unterstützen. Stackoverflow.com/questions/1141015/…
Ospho
Dies ist keine großartige Implementierung - ich würde Container vcs recherchieren
Adam Waite
0

Wenn Sie eine benutzerdefinierte UIView mit einer xib-Datei haben.

- (id)initWithFrame:(CGRect)frame
{
   self = [super initWithFrame:frame];

   id mainView;
   if (self)
   {
       NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"HomeAllAdsView" owner:self options:nil];
       mainView = [subviewArray objectAtIndex:0];    
   }
   return mainView;
}

- (void) awakeFromNib
{
   [super awakeFromNib];
}
felixwcf
quelle