2009-07-11 6 views
4

J'ai rencontré un comportement très étrange que je ne comprends pas. J'ai une classe Texture avec contentWidth propriété de type int. Cette classe est enveloppée dans une classe Image qui a une propriété width de type int. Le width d'un Image est calculé simplement comme le contentWidth de la texture sous-jacente:Valeurs dynamiques de saisie et de retour dans Objective-C

- (int) width 
{ 
    return texture.contentWidth; 
} 

Maintenant, le Image est utilisé par une classe Button (par la composition, pas l'héritage) qui veut lire la taille de l'image:

// image is of type ‘id’ 
int width = [image width]; 
int height = [image height]; 

Le problème est que la variable height est définie correctement, tandis que la variable width contient NaN (-2147483648). J'ai vérifié les dimensions - ils sont environ 200 × 100 ou plus, loin de la limite int. En outre, l'infobulle du débogueur Xcode affiche correctement les deux propriétés dans le Texture, mais seulement après que la largeur ait traversé les deux accesseurs, le numéro est brouillé. Les objets ne sont pas libérés. Qu'est-ce que je rate?


Mise à jour: J'ai élargi l'accesseur dans la classe Image pour voir où le problème provient:

- (int) width 
{ 
    const int w = texture.contentWidth; 
    return w; 
} 

Maintenant, quand je pause sur la première ligne, le w correctement obtient l'ensemble. Je fais un pas sur les déclarations d'exécution à la fonction appelante:

- (void) foo 
{ 
    int bar = [image width]; 
} 

... et maintenant le bar contient NaN.


Mise à jour: Hmm, il a obtenu:

int foo = [image width]; // image is id, returns NaN 
int bar = [(Image*) image width]; // correct value 

Le image est déclarée comme id, qui est le point ici. Quelqu'un pourrait-il expliquer cela? J'ai le sentiment que je n'appelle pas la bonne méthode, mais que se passe-t-il exactement ici? Je tape toujours mes variables aussi strictement que possible, mais ici le type id est pratique. Je n'avais aucune idée que cela pourrait entraîner un tel bug.

+0

Avez-vous implémenté un accesseur contentWidth dans votre classe Texture? –

+0

Quelle est la différence entre les accesseurs de largeur et de hauteur? Comment l'accesseur de hauteur est-il implémenté dans Image? – Tim

+0

@Tim: Il n'y a pas de différence, l'accesseur 'height' est exactement le même. Sauf pour les noms, bien sûr :) – zoul

Répondre

5

Oh bien. Si vous êtes intéressé à savoir pourquoi cette situation se produit, consultez l'Objective-C Guide de programmation, chapitre 8, Return and Argument Types:

En général, les méthodes dans différentes classes qui ont le même sélecteur (du même nom) doit aussi partager les mêmes types de retour et d'argument.Cette contrainte est imposée par le compilateur pour permettre la liaison dynamique. Parce que la classe d'un récepteur de message (et détails donc spécifiques à chaque classe sur la méthode, il est demandé d'effectuer), ne peut pas être connu au moment de la compilation, le compilateur doit traiter toutes les méthodes avec même Alike nom. Lorsqu'il prépare des informations sur le retour de méthode et des types d'argument pour le système d'exécution, il crée une seule description de méthode pour chaque sélecteur de méthode.

Cependant, lorsqu'un message est envoyé à un objet de type statique , la classe de le récepteur est connue par le compilateur. Le compilateur a accès à des informations spécifiques à la classe sur les méthodes . Par conséquent, le message est libéré des restrictions sur ses types de retour et d'argument .

Voici un bug report dans le bugzilla GCC (et un blog post correspondant). Le comportement n'est pas un bug, mais il n'est pas non plus très convivial, car le compilateur ne vous avertit pas (du moins pas avec les paramètres d'alerte par défaut).

1

Si pas votre accesseur être:

- (int) width 
{ 
    return [texture contentWidth]; 
} 

Est texture une variable d'instance? Si c'est le cas, avez-vous fait super pour l'initialiser dans la méthode init ou votre classe wrapper?

+2

Les deux sont équivalents - Objective-C convertira la syntaxe de l'accesseur de point en un message transmis lors de la compilation. – Tim

+0

C'est une bonne idée de toute façon d'un point de vue "bonne pratique" ... Dans ce cas, je m'assurerais que votre instance est correctement initialisée. – micmoo

+0

Je viens de surcharger la méthode 'description' sur la classe Texture et j'en ai enregistré les dimensions, elles vont bien. – zoul

Questions connexes