2013-09-02 10 views
11

Ich habe eine Klasse, FooView, dass eine Unterklasse von UIView ist, und deren Ansicht von einer Feder belastet ist, so etwas wie:eine UIView Unterklasse Vererben von einer Feder geladen

+ (instancetype)viewFromNib 
{ 
    NSArray *xib = [[NSBundle mainBundle] loadNibNamed:@"FooView" owner:self options:nil]; 
    return [xib objectAtIndex:0]; 
} 

Die Spitze selbst hat seine Gewohnheit Die Klasse wurde im Identity Inspector auf FooView festgelegt.

Dies wird instanziiert wie:

FooView *view = [FooView viewFromNib]; 

Dies verhält sich wie man erwarten würde. Wenn jedoch FooView sich als FooSubclassView subclassed ist, und instanziiert wie:

FooSubclassView *view = [FooSubclassView viewFromNib]; 

view ist nach wie vor vom Typ FooView, nicht FooSubclassView.

die Klasse mit object_setClass Swizzling beheben nicht die Tatsache, dass das zugrunde liegende Objekt eine Instanz FooView ist, und damit auf der Unterklasse-Instanz aufgerufen Methoden werden die von der übergeordneten Klasse (FooView), nicht FooSubclassView.

Wie kann ich das korrigieren, so dass Unterklassen vom richtigen Typ sind, ohne dass für jede Unterklasse eine neue Nib erstellt werden muss oder in jeder Unterklasse viewFromNib neu implementiert werden muss?

Antwort

7

Swizzling ist (niemals) die Antwort.

Das Problem liegt in Ihrer NIB; Es wird archiviert, wobei das Objekt [0] eine Instanz von FooView, nicht FooSubclassView ist. Wenn Sie die selbe NIB mit einer verschiedenen View-Unterklasse als Objekt [0] laden möchten, müssen Sie die Instanz aus dem NIB-Archiv verschieben.

Wahrscheinlich die einfachste Sache zu tun, da die Klasse bereits die NIB laden, ist eine Instanz von FooView oder FooSubclassView der Besitzer Datei machen.

Diese Frage hat eine anständige Erklärung der Datei Besitzer Muster. Beachten Sie, dass Sie ziemlich genau dort sind, wo Ihre Klasse ist, was die XIB/NIB sowieso lädt.

Und hier ist der offizielle docs on File's Owner.

+0

Ich verstehe das nicht genau. Wenn es sich bei der Ansicht um den Dateibesitzer handelt, benötigen Sie eine andere Klasse, die die visuelle "Leinwand" darstellt, auf der Sie IB verwenden, oder? Entschuldigung, wenn diese Frage nicht klar ist, aber ich habe eine NIB mit nur einer einzigen NSView-Unterklasse. Vielen Dank! –

1

Ich bin mir nicht sicher, ob Sie auf die beste Lösung, aber ich denke, das ist, was Sie suchen.

+ (instancetype)viewFromNib 
{ 
    NSString *className = NSStringFromClass([self class]); 
    NSArray *xib = [[NSBundle mainBundle] loadNibNamed:className owner:self options:nil]; 
    return [xib objectAtIndex:0]; 
} 

Das ist so lange wie Sie sicher sein können, dass die NIB den gleichen Namen wie die Klasse hat.

Nachdem ich realisiert habe, dass ich eine der Anforderungen falsch verstanden habe, sage ich, dass ich @bbum zustimmen muss.

- (id)init 
{ 
    // NOTE: If you don't know the size, you can work this out after you load the nib. 
    self = [super initWithFrame:GCRectMake(0, 0, 320, 480)]; 
    if (self) { 
     // Load the nib using the instance as the owner. 
     [[NSBundle mainBundle] loadNibNamed:@"FooView" owner:self options:nil]; 
    } 
    return self; 
} 

+ (instancetype)viewFromNib 
{ 
    return [[self alloc] init]; 
} 
+0

Das wird nicht funktionieren; Sie laden die NIB mit dem Namen 'className', was bedeutet, dass Sie eine NIB pro Klasse benötigen. Zumindest glaube ich nicht, dass OP das will. Aber vielleicht ist es ... – bbum

+0

Nun verdammt, ich habe diese Anforderung nicht bemerkt. –

Verwandte Themen