J'ai essayé de compiler, mais chaque fois que je le fais, une méthode génère une erreur étrange "attendue d'un type". J'ai une méthode dans l'en-tête:
-(ANObject *)generateSomethingForSomethingElse:(NSString *)somethingElse;
L'erreur pointe sur le type de retour pour cette méthode. J'ai importé ANObject
dans l'en-tête en utilisant #import "ANObject.h"
et ANObject
compile bien ..
Pourquoi cela arrive-t-il?
Ceci est lié à l'ordre dans lequel les fichiers source sont compilés. Vous savez probablement déjà que vous ne pouvez pas appeler une méthode avant qu'elle soit définie (voir le pseudocode ci-dessous):
var value = someMethod();
function someMethod()
{
...
}
Cela provoquerait une erreur lors de la compilation car someMethod () n'a pas encore été défini. La même chose est vraie des classes. Les classes sont compilées les unes après les autres par le compilateur.
Donc, si vous imaginez que toutes les classes soient placées dans un fichier géant avant la compilation, vous pourrez peut-être déjà voir le problème. Regardons les classes Ship
et BoatYard
:
@interface BoatYard : NSObject
@property (nonatomic, retain) Ship* currentShip;
@end
@interface Ship : NSObject
@property (nonatomic, retain) NSString* name;
@property (nonatomic, assign) float weight;
@end
Encore une fois, comme la classe Ship
n'a pas encore été définie, nous ne pouvons pas encore y faire référence. Résoudre ce problème particulier est assez simple. changer l'ordre de compilation et compiler. Je suis sûr que vous connaissez bien cet écran en XCode:
Mais savez-vous que vous pouvez faire glisser les fichiers de haut en bas dans la liste? Cela change l'ordre dans lequel les fichiers seront compilés. Par conséquent, déplacez simplement la classe Ship
au-dessus de la classe BoatYard
, et tout va bien.
Mais que se passe-t-il si vous ne voulez pas faire cela, ou plus important encore, s'il y a une relation circulaire entre les deux objets? Augmentons la complexité de ce diagramme d'objets en ajoutant une référence à la BoatYard
courante dans laquelle se trouve la Ship
:
@interface BoatYard : NSObject
@property (nonatomic, retain) Ship* currentShip;
@end
@interface Ship : NSObject
@property (nonatomic, retain) BoatYard* currentBoatYard;
@property (nonatomic, retain) NSString* name;
@property (nonatomic, assign) float weight;
@end
Oh mon Dieu, maintenant nous avons un problème. Ces deux ne peuvent pas être compilés côte à côte. Nous avons besoin d'un moyen d'informer le compilateur que la classe Ship * existe réellement. Et c'est pourquoi le mot clé @class
est si pratique.
En termes simples, vous dites: "Faites-moi confiance, Ship
existe vraiment, et vous le verrez très vite". Pour tout mettre ensemble:
@class Ship;
@interface BoatYard : NSObject
@property (nonatomic, retain) Ship* currentShip;
@end
@interface Ship : NSObject
@property (nonatomic, retain) BoatYard* currentBoatYard;
@property (nonatomic, retain) NSString* name;
@property (nonatomic, assign) float weight;
@end
Maintenant, le compilateur sait en compilant BoatYard
qu'une définition de classe Ship
apparaîtra bientôt. Bien sûr, si ce n’est pas le cas, la compilation réussira quand même.
Cependant, tout le mot clé @class
informe le compilateur que la classe arrivera bientôt. C'est pas un remplacement pour #import
. Vous devez toujours importer le fichier d'en-tête ou vous n'aurez accès à aucun des internes de la classe:
@class Ship
-(void) example
{
Ship* newShip = [[Ship alloc] init];
}
Cela ne peut pas fonctionner et échouera avec un message d'erreur indiquant que Ship est une déclaration aval. Une fois que vous avez #import "Ship.h"
, vous pourrez alors créer l'instance de l'objet.
J'ai trouvé cette erreur quand il y a une dépendance circulaire sur les en-têtes. Vérifiez si le fichier .h dans lequel vous déclarez cette méthode est importé dans ANObject.h
Vous ajoutez essentiellement
@class ANObject;
avant @interface!
Donc, pour une raison quelconque, je recevais cette erreur en essayant de définir une méthode avec un type enum dans les paramètres. Ainsi:
- (void)foo:(MyEnumVariable)enumVariable;
Je l'avais précédemment utilisé comme ça et je n'avais jamais eu de problème, mais maintenant je l'ai fait. J'ai vérifié la dépendance circulaire et n'ai pu en trouver aucune. J'ai également vérifié les fautes de frappe à plusieurs reprises et pas de dés. Ce qui a fini par résoudre mon problème, c’est d’ajouter «enum» avant que je veuille accéder à la variable. Ainsi:
- (void)foo:(enum MyEnumVariable)enumVariable;
{
enum MyEnumVariable anotherEnumVariable;
}
J'ai reçu ce message lorsque le type de variable a été mal orthographié. Voir ci-dessous ceci ci-dessous
par exemple.
-(void)takeSimulatorSafePhotoWithPopoverFrame:(GCRect)popoverFrame {
au lieu de.....
-(void)takeSimulatorSafePhotoWithPopoverFrame:(CGRect)popoverFrame {
Habituellement, lorsque je vois une erreur comme celle-ci, c'est parce que j'ai une faute de frappe sur une ligne précédente, telle qu'une parenthèse supplémentaire ou manquante, etc.
Cela peut sembler stupide, mais un mauvais pilonnage ou une mauvaise utilisation de lettres en majuscules/minuscules est le cas.
Curieusement, changer l'ordre de mes importations a corrigé cela dans le passé ... Essayez de déplacer l'importation au bas de la liste après toutes vos autres importations.