Structure de donnée et NSData

CeetixCeetix Membre
février 2010 modifié dans API AppKit #1
Hello,


Voilà  j'ai une petite question.
J'ai une structure de donnée :


<br />typedef struct Data{<br />	int idn;<br />	int msg;<br />}Data;<br />



J'aimerai mettre mes variables de ce type dans un NSData, je vois pas trop comment mettre une variable dedans.
J'ai fais ça :


<br />Data *aD;<br />aD-&gt;idn = message-&gt;idn;<br />aD-&gt;msg = message-&gt;msg;<br />NSData *data = [NSData dataWithBytes:&amp;aD length:sizeof(Data *)];<br />



Est-ce bien correcte ? Si oui comment le décrypter derrière ?
Car j'aimerai ensuite m'en servir pour envoyer cette donnée via wifi à  l'autre device pour qu'il puisse décoder ça .

Réponses

  • AliGatorAliGator Membre, Modérateur
    20:48 modifié #2
    C'est presque ça, sauf que tu as un niveau d'indirection en trop.

    Le type "Data" n'est pas un NSObject comme des objets Cocoa, c'est une structure C ("struct"). Donc si tu déclares "Data*" tu déclares un pointeur vers une structure, mais il faut l'initialiser (avec malloc) et faudra penser à  la relâcher (avec free), un peu comme tu ferais "alloc/init" et "release" avec un objet Cocoa. Et en plus c'est alors directement le pointeur qu'il faudra passer à  dataWithBytes, au risque d'encoder le pointeur vers ton "Data" et non pas le contenu du "Data" lui-même, ce qui perd tout son intérêt...

    Donc le plus simple est de ne pas manipuler des "Data*" mais juste des "Data" (puisque ce sont juste des struct C, comme tu manipulerais des int ou des float directement, quoi et pas des int* ou float*) :
    Data aD; // plus de &quot;*&quot; ici<br />ad.idn = ...; // du coup des &quot;.&quot; pour accéder aux champs de la structure, et non plus des &quot;-&gt;&quot;<br />ad.msg = ...;<br />NSData* data = [NSData dataWithBytes:&amp;aD length:sizeof(Data)];<br />// on passe bien l&#39;adresse de aD &quot;&amp;aD&quot;, aD étant un &quot;Data&quot;, &amp;aD est bien un &quot;Data*&quot; donc un pointeur vers tes données<br />// on passe bien sizeof(Data), taille de tes données (et non pas taille du pointeur qui pointe vers ces données)
    
  • AliGatorAliGator Membre, Modérateur
    20:48 modifié #3
    Au fait, je ne sais pas dans quel but tu veux "wrapper" ces données dans du NSData, si c'est pour les envoyer par le réseau, pour les sauver sur disque, pour les passer dans un pipe ou à  un autre process, ... mais il peut être intéressant de lire les docs relatives au sujet en question car selon le cas une façon de faire peut être plus appropriée qu'une autre. Par exemple si c'est pour créer une archive de tes données (genre sauver tes données dans un document), c'est plutôt avec NSCoder (et NSKeyedArchiver/NSKeyedUnarchiver) qu'il faut travailler pour sérialiser tes données et les sauver sur disque, et les désérialiser dans l'autre sens ensuite.

    Si c'est pour envoyer sur du réseau, NSData peut en effet être plus apporprié, fais juste gaffe à  ce que les deux parties que tu vas faire communiquer utilisent la même endianness (LittleEndian/BigEndian). Si par exemple ce sont un MacIntel et un iPhone, c'est le cas, mais un Mac Intel et un Mac PPC ce n'est pas le cas.

    Sinon, pour retransformer ton NSData en struct, il suffit de récupérer les octets encapsulés dans ce NSData, et de les caster en Data :
    // la méthode &#39;bytes&#39; de NSData retourne un pointeur vers les données<br />struct Data* paD = (struct Data*)[monNsData bytes]; // on &quot;cast&quot; le pointeur dans le type attendu<br />struct Data aD = *paD; // et on lit récupère le contenu des données pointées par ce pointeur
    
    ou plus directement
    struct Data aD = *(struct Data*)[myNsData bytes];
    
  • CeetixCeetix Membre
    20:48 modifié #4
    Super Ali !
    Merci beaucoup pour ces explications !
    Je me demandais un truc aussi. Là  je reçois avec mon mac mon Data, mais si je veux le recevoir avec un serveur windows, il ne pourra jamais décrypter mon Data que j'envoie vu que je le fais via NSData. Si ?
  • AliGatorAliGator Membre, Modérateur
    20:48 modifié #5
    Si. Ce n'est pas un NSData que tu envoies en fait. Ce sont juste des données binaires, des octets en série quoi.
    NSData est un objet Cocoa pour manipuler les flux d'octets, ce n'est qu'un objet bien pratique pour manipuler ces données.

    Mais on ne peut pas dire que tu "envoies tes NSData dans le socket (sur le réseau)" : c'est juste que la méthode que tu utilises, pour envoyer tes données sur le réseau, prend j'imagine (je sais pas quelle méthode tu utilises en fait) un NSData en paramètre, parce que c'est quand même bien plus simple à  manipuler pour toi que de manipuler des NSData dans des méthodes Cocoa quoi. Mais en réalité tu "envoies des octets dans le socket (sur le réseau)" donc les octets contenus dans ton NSData.

    Tu utiliserais une autre API que Cocoa, par exemple les APIs C directement, tu manipulerais tes octets à  envoyer sous forme de "char*" ou "void*", mais ça marcherait pareil.

    Donc de l'autre côté, que tu aies un Mac, un Windows, un Linux, etc... ça change rien. Tu utilises l'API que tu veux, du moment qu'à  un moment donné tu puisses récupérer tes octets (que l'API les encapsule dans un NSData ou un autre objet... ou pas).
  • CeetixCeetix Membre
    20:48 modifié #6
    Hum ok je pense saisir. Le NSData ne me sert qu'à  simplifier mon envoie d'octet mais au final ce n'est pas lui qui transite mais bien mes octets de donnée.
  • CéroceCéroce Membre, Modérateur
    20:48 modifié #7
    Méfie-toi des structures, le compilateur peut très bien ajouter des octets d'alignement pour des questions de performance.
    Il y a aussi le problème d'Endianness.

    D'habitude, on utilise plutôt un buffer dans lequel on sérialise les octets avant de l'envoyer sur le réseau.
Connectez-vous ou Inscrivez-vous pour répondre.