Retourner un type inconnu.

Salut,
Je suis en train de me faire une petite classe sympas dont je vous parlerais quand ce sera sur mon github
/tongue.png' class='bbc_emoticon' alt=':P' />.
Et en fait j'aurais besoin d'une méthode qui me retourne une valeur, mais dont je connais pas le type...
ça peut être aussi bien un objet (id), qu'un int, un float, un bool, un double, etc... À peu près n'importe quel type c (pas de tableau, pas de pointeurs, juste des types primitifs de base).
Bon déjà j'ai fait deux méthode pour séparer les types C et les objet (id), afin de simplifier le truc.
Pour les objets du coup ça marche bien, y'avait pas de grande difficulté sur ce point.
Par contre, pour les types primitifs c'est plus compliqué. J'ai essayé de me baser sur le fonctionnement de NSValue, donc avec un passage de référence et en renseignant le type (avec @encode). Mais j'arrive pas à ce que je veux.
La seule chose qui fonctionne, c'est en utilisant justement un NSValue. Mais ça me plait pas trop, j'aurais préféré comprendre le fonctionnement du NSValue en interne afin de pouvoir faire à peu près la même chose.
Voilà un peu le genre de code que j'ai (c'est un ptit projet de test que j'ai fais via CodeRunner) :
Avec ça j'obtiens grosso ce que je veux puisque ça me retourne
Mais voilà , comment faire sans les NSValue ?
Je suis en train de me faire une petite classe sympas dont je vous parlerais quand ce sera sur mon github
Et en fait j'aurais besoin d'une méthode qui me retourne une valeur, mais dont je connais pas le type...
ça peut être aussi bien un objet (id), qu'un int, un float, un bool, un double, etc... À peu près n'importe quel type c (pas de tableau, pas de pointeurs, juste des types primitifs de base).
Bon déjà j'ai fait deux méthode pour séparer les types C et les objet (id), afin de simplifier le truc.
Pour les objets du coup ça marche bien, y'avait pas de grande difficulté sur ce point.
Par contre, pour les types primitifs c'est plus compliqué. J'ai essayé de me baser sur le fonctionnement de NSValue, donc avec un passage de référence et en renseignant le type (avec @encode). Mais j'arrive pas à ce que je veux.
La seule chose qui fonctionne, c'est en utilisant justement un NSValue. Mais ça me plait pas trop, j'aurais préféré comprendre le fonctionnement du NSValue en interne afin de pouvoir faire à peu près la même chose.
Voilà un peu le genre de code que j'ai (c'est un ptit projet de test que j'ai fais via CodeRunner) :
#import <Foundation/Foundation.h><br />
<br />
@interface Test : NSObject<br />
<br />
@property (nonatomic, assign) const char *type;<br />
- (void) getValue:(void *)value fromString:(NSString *)string;<br />
@end<br />
<br />
@implementation Test<br />
@synthesize type;<br />
<br />
- (void) getValue:(void *)bufferValue fromString:(NSString *)string<br />
{<br />
NSValue *valueObject;<br />
if (strncmp(self.type, @encode(int), 1) == 0) {<br />
int temp = [string intValue];<br />
valueObject = [NSValue value:&temp withObjCType:self.type]; //NSValue que j'aimerais éviter<br />
[valueObject getValue:bufferValue];<br />
}<br />
else if (strncmp(self.type, @encode(float), 1) == 0) {<br />
float temp = [string floatValue];<br />
valueObject = [NSValue value:&temp withObjCType:self.type]; //NSValue que j'aimerais éviter<br />
[valueObject getValue:bufferValue];<br />
}<br />
}<br />
<br />
@end<br />
<br />
int main(int argc, char *argv[]) {<br />
@autoreleasepool {<br />
Test *test = [Test new];<br />
<br />
test.type = @encode(int);<br />
<br />
int test_int;<br />
float test_float;<br />
<br />
[test getValue:&test_int fromString:@"42"];<br />
[test getValue:&test_float fromString:@"42"];<br />
<br />
NSLog(@"%i ; %f", test_int, test_float);<br />
<br />
test.type = @encode(float);<br />
<br />
[test getValue:&test_int fromString:@"42"];<br />
[test getValue:&test_float fromString:@"42"];<br />
<br />
NSLog(@"%i ; %f", test_int, test_float);<br />
}<br />
}<br />
Avec ça j'obtiens grosso ce que je veux puisque ça me retourne
2012-07-26 14:32:30.623 Untitled 2[31459:707] 42 ; 0.000000<br />
2012-07-26 14:32:30.637 Untitled 2[31459:707] 1109917696 ; 42.000000<br />
Mais voilà , comment faire sans les NSValue ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
De ce que j'imagine, la méthode -[NSValue getValue:] ne fait que récupérer un "void*" de la bonne taille en octets. A toi ensuite de le caster dans le bon type. Pas besoin de passer par NSValue pour ça, une simple affectation suffit !
Le but c'est de mettre dans l'emplacement mémoire pointé par le pointeur bufferValue, la valeur lue. Pour ça rien de plus simple :
Et c'est tout, pas besoin de plus. Faut juste pour pas que ça plante que tu passes un pointeur du bon type (ce que tu fais déjà , puisque tu passes &test_int pour lire un int, &test_float pour lire un float).
Bon après, pour info, si tu as besoin de connaà®tre la taille que prend un type en mémoire à partir de son Type Encoding, donc à partir de @encode(int) savoir combien prend un int, tu as la fonction C Foundation NSGetSizeAndAlignment si ça peut te servir... même si dans ton cas je ne pense pas que ce soit utile.
Car là , oui je donne bien le bon type. Mais dans ma classe j'ai même pas le bon type ! Tu pourrais donc me montrer comment faire avec un type inconnu pour la variable passer par référence à la méthode ?
Avec des méthodes de C (puisque le problème vient des types C)
Mais je dis peut-être une grosse bêtise... Dans ce cas, désolé!
Car la taille d'un int et d'un float en mémoire est la même, donc sizeof(int) == sizeof(float). Baser ça condition là -dessus pour caster est donc dangereux !
@JegnuX : Ah oui en effet, logique comme erreur. Mais bon, il suffit de caster ton pointeur pour le transformer de void* en int* ou float*, non ? Bon j'ai pas testé (code tapé en live) mais ça devrait marcher
Il y a les templates C++ qui pourraient regler ce probleme non ?
Si ca peu aider... je distribuerai sans souci.
Cétait un exo d'ecole.
Par-contre moi j'avais je me rappel que cétait beaucoup plus long comme fonction vu que je n'avais pas le droit a aucun appel syst.
Je regarde ca des que j'ai la main dessus.
Mais sinon dans mon example sur coderunner, la solution d'Ali semble fonctionner.
Faut juste que j'essaie de l'intégrer au vrai contexte qui est un poil plus compliqué.
Sauf que bon, si tu as un type inconnu, je me demande bien comment tu vas calculer ta valeur de "temp", là où dans ton exemple quand tu sais que c'est un int tu prend [string intValue] et si c'est un float tu prends [string floatValue]... dans le cas générique je sais pas ce que tu comptes prendre
Dans mon cas précis, c'est le runtime qui me dis quoi faire. En gros je fait de l'introspection sur les Ivar et @property.