Überschreiben einer readonly-Eigenschaft in der Unterklasse
Gibt es eine Klasse, die wie folgt aussieht (ich bin Wegfall der Importe aus Platzgründen):
Basis.h:
@interface Base : NSObject
@property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
@end
Basis.m:
@implementation Base
- (id)initWithSomething:(NSString *)something {
self = [super init];
if (self) _something = something;
return self;
}
@end
Als Sie sehen, die 'etwas' Eigenschaft readonly ist. Jetzt will ich erstellen Sie eine Unterklasse überschreibt die Eigenschaft beschrieben werden als gut:
Sub.h:
@interface Sub : Base
@property (strong) NSString *something;
@end
Sub.m:
@implementation Sub
@end
Und den code:
main.c:
int main(int argc, const char * argv[]) {
@autoreleasepool {
Sub *o = [Sub new];
o.something = @"foo";
NSLog(@"%@", o.something);
}
return 0;
}
Dieser code führt zu:
2013-09-07 13:58:36.970 ClilTest[3094:303] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '-[Sub setSomething:]: unrecognized
selector sent to instance 0x100109ff0'
Warum ist das so? Warum nicht, es finden die setSelector?
Wenn ich das in der Unterklasse statt:
Sub.m:
@implementation Sub
@synthesize something = _something;
@end
alles funktioniert. Bedeutet das, dass die Unterklasse' - Eigenschaft wird nicht synthetisiert standardmäßig, obwohl es ist definiert als @property
im @interface
? Funktioniert das kompilieren irgendwie "sehen" die automatisch erzeugten getter von der Basis und nicht erzeugen die setter? Und warum, ich denke, der setter erzeugt werden sollen, als es noch nicht existiert. Ich bin mit Xcode 4.6.2 und das Projekt ist ein Cli-Tool (Typ-Stiftung), aber das gleiche passiert auch in meinem aktuellen Projekt ist eine iPhone-app.
Hintergrund: ich habe ein schweres Objekt (eine Instanz der Basis), erfordert eine Bluetooth-Verbindung zu einigen Geräten und ich sollte das erstellen einer view-controller für einige Funktionen. Für einfache Tests möchte ich nicht angeschlossen werden, um BT (eigentlich bräuchte ich ein physisches Gerät und testen Sie den code drauf), ich möchte in der Lage sein, um es zu testen im simulator.
Was ich mir ausgedacht habe ist, dass ich Sie einfach erstellen Sie eine Unterklasse (Sub), die stubs ein paar Eigenschaften /Methoden und verwenden Sie stattdessen, und wenn der code fertig ist, ich entfernen Sie einfach den code für die Unterklasse, ersetzen Sie die Instanz mit dem richtigen, im test mit einem Gerät, commit und push. Es funktioniert eigentlich einwandfrei, bis auf die seltsame Sache mit @property
oben.
Könnte jemand mir sagen, was Los ist mit der Eigenschaft überschreiben?
- Neben der Lösung arbeiten, ich wollte noch hinzufügen, dass 'die Erhöhung' der Ebene der Privatsphäre ein Attribut geht gegen die OOP-Prinzipien. In der Regel (aber nicht immer), wenn Sie haben, um eine Immobilie mehr sichtbar (privat -> protected oder protected -> öffentlich) in einer Unterklasse, dann ist etwas falsch in das Modell. Das Gegenteil geschieht mit den Methoden. Wenn die übergeordnete Klasse hat Eine Methode, Sie sollten nicht machen Eine private (public -> protected oder protected -> privat) in einer Unterklasse.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Für eine readonly-Eigenschaft, nur eine get-Methode synthetisiert, aber keine setter-Methode.
Und bei der Erstellung der Unterklasse, die der compiler nicht wissen wie die Eigenschaft realisiert wird
in der Basis-Klasse (es könnte sich um einen benutzerdefinierten get-anstatt eine Unterlage, instance variable).
Also es kann nicht erstellen Sie einfach eine setter-Methode in der Unterklasse.
Wenn Sie möchten, um Schreibzugriff auf die gleichen Instanz-variable aus der Unterklasse,
Sie deklarieren es als
@protected
in der base-Klasse(so, dass es zugänglich ist, in der Unterklasse), re-deklarieren Sie die Eigenschaft
wie Lesen und schreiben in der Unterklasse, und eine setter-Methode:
Basis.h:
Sub.h:
Sub.m:
Ihre Lösung
erzeugt getter-und setter-Methode in der Unterklasse, mit einem separate Instanz
variable
_something
in der Unterklasse (die ist andersvon
_something
in der base-Klasse).Dieser funktioniert auch, nur sollte man sich bewusst sein, dass
self.something
bezieht sich aufverschiedene Instanz-Variablen in der Basisklasse und in der Unterklasse. Zu machen, dass
deutlicher, Sie könnte Verwendung einer anderen Instanz-variable in der Unterklasse:
@synthesize
- Anweisung für die Eigenschaft in der Basis.m?Die gegebene Antwort funktioniert einwandfrei. Dies ist eine alternative Antwort, dass anscheinend Apple gerne ein bisschen mehr.
Können Sie festlegen, private Erweiterung Ihrer Klasse, einer
Base+Protected.h
- Datei, die enthalten sein müssen inBase.m
undSub.m
.Dann, in dieser neuen Datei, die Sie neu definieren der Eigenschaft als
readwrite
.Diese alternative ermöglicht die Verwendung von accessor -
self.something
rathern als die ivar_something
.Hinweis: Sie müssen noch zu halten, die definition von
something
in IhremBase.h
wie Sie ist.Ich denke, dass die backing-Variablen sind die gleichen, wenn die Eigenschaft wird nicht synthetisiert, die in der Unterklasse. So zur Laufzeit das programm versucht, rufen Sie die setSomething in der Oberklasse. Aber da es nicht existiert wird eine Ausnahme geworfen.