2009-12-16 15 views
1

J'ai rencontré un scénario étrange lié à l'héritage de classe dans Objective-C.Méthode d'héritage Objective-C correspondant

Disons que j'ai trois classes A, B et C héritant d'une classe de base X. Les classes A, B et X ont le constructeur:

- (id)InitWithString:(NSString*)someString andDelegate:(id<SomeProtocol>)aDelegate 

la seule différence étant que chaque classe utilise un autre protocole pour le délégué. Qu'est-ce qui se passe est que pour A et B le compilateur essaie d'utiliser la méthode de C. Un avertissement m'informe que les protocoles requis par le constructeur de la classe C n'est pas implémenté par le délégué fourni. Il n'y a rien de mal avec le délégué lui-même, puisque chaque classe a un délégué qui implémente le bon protocole pour le propre constructeur des classes. Tout fonctionne bien à l'exécution et les bonnes fonctions sont appelées pour toutes les classes.

J'ai essayé que les constructeurs retournent A *, B * ou C * au lieu de l'identifiant anonyme, bien que cela ne résout toujours pas le problème.

La seule chose qui fonctionne est de faire un casting à la bonne classe comme ceci:

instanceOfA = [(A*)[A alloc] InitWithString:@"" andDelegate:aDelegate]; 

Cela semble superflu et inutile. Il me manque probablement quelque chose d'évident ici.

+1

Ne jamais nommer une méthode avec une majuscule initiale, c'est une abomination. Aussi, vous ne devriez pas utiliser * et * dans le nom. Dans C# le nom 'InitWithStringAndDelegate()' est bon et bon, dans Objective-C il devrait être 'initWithString: delegate:'. – PeyloW

+0

Ouais, utiliser "et" est généralement une mauvaise idée car vous devez le changer si vous ajoutez un autre paramètre. Le capital initial est principalement une question de goût et de convention. Je ne ressens aucune obligation de suivre la convention d'Apple, d'autant plus que cela m'aide à identifier facilement mes propres méthodes dans une classe qui sous-classe une classe Cocoa. Cependant, tout cela est hors sujet :) –

Répondre

1

Je ne suis pas sûr de savoir comment l'analyseur est réellement pour ces cas et vous soupçonnez que vous avez simplement frappé l'une de ses limites.

Ce que vous observez est le compilateur voyant l'objet comme id et choisissant la première méthode qui correspond à la signature. Essayez de déplacer l'ordre dans lequel vous incluez vos classes et vous devriez voir qu'il sélectionne toujours le sélecteur défini en premier.

Une façon de contourner cela est d'initialiser la classe en deux étapes:

ClassA *test = [ClassA alloc]; 
test = [test initWithString:@"" andDelegate:delegate]; 

Dans ce cas, l'analyseur sait test est de type ClassA et choisit le sélecteur à droite. Il semble que ce n'est pas si malin de dire de quel type sont les objets intermédiaires qui ne sont pas assignés à une variable et ensuite les suppose toujours id.

+0

C'est absolument correct. Je suis sûr que le fait que l'avertissement est produit dans seulement 2 de mes 3 classes a seulement à faire avec l'ordre d'inclure. Votre solution avec la division de l'initialisation fonctionne également, bien que cela semble encore excessif. –

+0

Une méthode de classe pourrait fonctionner aussi, bien que je n'ai pas testé ceci: 'ClassA * test = [[ClassA classAWithString: @" "andDelegate: delegate] conserve]' Qui a le même résultat mais est seulement une ligne longue . – Adrian

1

Le problème est avec la déclaration de la méthode qui définit un paramètre d'un type spécifié.

Vous devez rendre la déclaration aussi générique que possible pour être valide pour toutes les classes de l'objet passé en dernier paramètre. Si tout le protocole hérite d'un protocole parent, vous pouvez déclarer la méthode comme - (id)initWithString:(NSString*)someString andDelegate:(id<ParentProtocol>)aDelegate; différemment, vous pouvez utiliser la définition plus générique - (id)initWithString:(NSString*)someString andDelegate:(id)aDelegate

+0

Eh bien dans ce cas, je perds l'option d'appliquer un protocole spécifique dans mon initialisation. Je ne peux pas voir la logique derrière cela.Puisque je suis autorisé à exiger un paramètre d'un type spécifique NSString * au lieu de NSObject * ou id, pourquoi ne puis-je pas décider d'exiger id ? Pour clarifier, mes délégués n'héritent d'aucun autre délégué. Une erreur s'est également produite dans l'instruction de problème. Ma classe de base X a un initialiseur différent et ne sait rien des délégués. –

+0

Est-ce que les protocoles utilisés ont des méthodes communes? – kiamlaluno

+0

Ils n'ont aucune méthode en commun –