Im Allgemeinen erstellen Sie in Objective-C einen designierten Initialisierer für jede Klasse und dann verwenden Unterklassen den gleichen Initialisierer. Anstatt also initAnimal und initDog zu verwenden, verwenden Sie einfach init. Der Hund Unterklasse würde dann seine eigene Methode init definieren und die bezeichnete initializer in seiner übergeordneten Klasse aufrufen:
@implementation Dog
-(id)init
{
if((self = [super init])) { // call init in Animal and assign to self
// do something specific to a dog
}
return self;
}
@end
Sie haben nicht wirklich initDog und initAnimal angeben, da die Klasse auf der rechten Seite der erklärt wird, Zuordnung ...
Update: ich füge die folgende auf die Antwort zu reflektieren die zusätzliche Informationen in der Frage
Es gibt eine Reihe von Möglichkeiten, um sicherzustellen, dass Unterklassen nicht nennen initializers andere als ihr designierter Initialisierer und die Art, wie du Ultimate machst ely wählen wird weitgehend auf Ihrem gesamten Design basieren. Eines der schönen Dinge an Objective-C ist, dass es so flexibel ist. Ich werde Ihnen zwei Beispiele geben, um Ihnen den Einstieg zu erleichtern.
Wenn Sie zuerst eine Unterklasse erstellen, die einen anderen als die übergeordnete Klasse als Initialisierer hat, können Sie den Initialisierer des übergeordneten Elements überladen und eine Ausnahme auslösen. Dies wird Programmierer sofort wissen lassen, dass sie das Protokoll für Ihre Klasse verletzt haben ... aber es sollte angegeben werden, dass Sie einen guten Grund dafür haben sollten und dass es sehr gut dokumentiert sein sollte, dass die Unterklasse dies kann verwende nicht denselben Initialisierer wie die Oberklasse.
@implementation Dog
-(id)init
{
// Dog does not respond to this initializer
NSAssert(false, @"Dog classes must use one of the designated initializers; see the documentation for more information.");
[self autorelease];
return nil;
}
-(id)initWithFur:(FurOptionsType)furOptions
{
if((self = [super init])) {
// do stuff and set up the fur based on the options
}
return self;
}
@end
Eine andere Möglichkeit, es zu tun ist Initialisierer mehr wie Ihr ursprüngliches Beispiel zu haben. In diesem Fall könnten Sie die Standardinitialisierung für die Elternklasse so ändern, dass sie immer fehlschlägt. Sie könnten dann einen privaten Initialisierer für Ihre Elternklasse erstellen und dann sicherstellen, dass jeder den entsprechenden Initialisierer in Unterklassen aufruft.Dieser Fall ist offensichtlich komplizierter:
@interface Animal : NSObject
-(id)initAnimal;
@end
@interface Animal()
-(id)_prvInitAnimal;
@end
@interface Dog : Animal
-(id)initDog;
@end
@implementation Animal
-(id)init
{
NSAssert(false, @"Objects must call designated initializers; see documentation for details.");
[self autorelease];
return nil;
}
-(id)initAnimal
{
NSAssert([self isMemberOfClass:[Animal class]], @"Only Animal may call initAnimal");
// core animal initialization done in private initializer
return [self _prvInitAnimal];
}
-(id)_prvInitAnimal
{
if((self = [super init])) {
// do standard animal initialization
}
return self;
}
@end
@implementation Dog
-(id)initDog
{
if((self = [super _prvInitAnimal])) {
// do some dog related stuff
}
return self;
}
@end
Hier können Sie die Schnittstelle und Implementierung der Tier- und Hunde-Klasse. Das Animal ist das designierte Objekt auf oberster Ebene und überschreibt daher die Implementierung von init durch NSObject. Jeder, der init für ein Animal oder eine der Unterklassen von Animal aufruft, erhält einen Assertion-Fehler, der sie auf die Dokumentation verweist. Animal definiert außerdem einen privaten Initialisierer für eine private Kategorie. Die private Kategorie würde mit Ihrem Code beibehalten und Unterklassen von Animal würden diesen privaten Initialisierer aufrufen, wenn sie Super aufrufen. Der Zweck ist, init in der Superklasse von Animal (in diesem Fall NSObject) aufzurufen und generische Initialisierungen durchzuführen, die notwendig sein könnten.
Schließlich ist die erste Zeile in der initAnimal-Methode von Animal eine Behauptung, dass der Empfänger tatsächlich ein Animal und nicht irgendeine Unterklasse ist. Wenn der Empfänger kein Tier ist, wird das Programm mit einem Assertionsfehler fehlschlagen und der Programmierer wird auf die Dokumentation verwiesen.
Dies sind nur zwei Beispiele, wie Sie etwas mit Ihren spezifischen Anforderungen entwerfen können. Allerdings würde ich stark vorschlagen, dass Sie Ihre Design-Einschränkungen berücksichtigen und sehen, ob Sie wirklich diese Art von Design benötigen, da es nicht-Standard in Cocoa und in den meisten OO-Design-Frameworks ist. Sie können zum Beispiel verschiedene Objekte auf Root-Level-Ebene erstellen und stattdessen einfach ein Animal-Protokoll verwenden, bei dem alle verschiedenen "Tiere" auf bestimmte generische Tiernachrichten reagieren müssen. Auf diese Weise kann jedes Tier (und wahre Unterklassen von Animal) selbst mit seinen Initiatoren umgehen und muss sich nicht auf Superklassen verlassen, die sich so spezifisch und nicht standardgemäß verhalten.
Okay Zoul, ich habe Updates zu meiner Antwort basierend auf den Updates zu Ihrer Frage gemacht ... es ist jetzt ziemlich lang, aber ich hoffe, es gibt Ihnen einige der Erkenntnisse, die Sie gesucht haben. –
Da dies ein Top-Ergebnis ist. Die Antwort im modernen XCode kann man mit NS_UNAVAILABLE erreichen. Siehe: http://stackoverflow.com/questions/195078/is-it-possible-to-make-the-init-method-private-in-objective-c#answer-27693034 – m4js7er