Question

Je travaille avec Objective-C et je dois ajouter INT d'un NSArray à un NSMutableData (je prépare un pour envoyer les données sur une connexion). Si j'Envelopper les INT avec NSNumber puis les ajouter à NSMutableData, comment pourrais-je savoir combien d'octets sont dans le NSNumber int? Serait-il possible d'utiliser sizeof () car, selon la documentation de pomme, « NSNumber est une sous-classe de NSValue qui offre une valeur un scalaire C (numérique). »?

Exemple:

NSNumber *numero = [[NSNumber alloc] initWithInt:5];

NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0];

[data appendBytes:numero length:sizeof(numero)];
Était-ce utile?

La solution

est pas un numero valeur numérique, il est un pointeur vers un objet represting une valeur numérique. Ce que vous essayez de faire ne fonctionne pas, la taille sera toujours égal à un pointeur (4 pour 32 plates-formes de bits et 8 pour 64 bits), et vous ajoutera une valeur de pointeur de déchets à vos données par rapport au nombre.

Même si vous deviez essayer de déréférencer, vous ne pouvez pas accéder directement aux octets soutenant un NSNumber et espérer qu'il fonctionne. Ce qui se passe est un détail de mise en œuvre interne et peut varier d'une version à l'autre ou même entre les différentes configurations de la même version (32 bits vs 64 bits, iPhone vs Mac OS X, bras vs vs PPC i386). Il suffit d'emballer les octets et les envoyer sur le fil peut entraîner quelque chose qui ne désérialiser pas correctement l'autre côté, même si vous avez réussi à obtenir des données réelles.

Vous avez vraiment besoin de trouver un codage d'un entier que vous pouvez mettre dans vos données, puis emballer et déballer les NSNumbers dans cela. Quelque chose comme:

NSNumber *myNumber = ... //(get a value somehow)
int32_t myInteger = [myNumber integerValue]; //Get the integerValue out of the number
int32_t networkInteger = htonl(myInteger); //Convert the integer to network endian
[data appendBytes:&networkInteger sizeof(networkInteger)]; //stuff it into the data

Du côté de la réception, vous prenez alors le nombre entier et recréez un NSNumber avec numberWithInteger. Après avoir utilisé ntohl pour le convertir au format hôte natif

Il peut exiger un peu plus de travail si vous essayez d'envoyer des représentations minimales, etc.

L'autre option consiste à utiliser une sous-classe NSCoder et dire au NSNumber de se coder en utilisant votre codeur, puisque ce sera la plate-forme neutre, mais il peut être trop pour ce que vous essayez de faire.

Autres conseils

En premier lieu, NSNumber * numero est "un pointeur vers un type NSNumber", et du type NSNumber est un objet Objective-C. En général, sauf indication spécifique quelque part dans la documentation, la règle de base dans la programmation orientée objet est que « les détails internes de la façon dont un objet choisit de représenter son état interne est privé à la mise en œuvre des objets, et doivent être traités comme un noir boîte." Encore une fois, à moins que la documentation indique que vous pouvez faire autrement, vous ne pouvez pas supposer que NSNumber utilise un type primitif C de int pour stocker la valeur de int vous lui avez donné.

Ce qui suit est une approximation grossière de ce qui se passe « dans les coulisses » lorsque vous appendBytes:numero:

typedef struct {
  Class isa;
  double dbl;
  long long ll;
} NSNumber;

NSNumber *numero = malloc(sizeof(NSNumber));
memset(numero, 0, sizeof(NSNumber));
numero->isa = objc_getClass("NSNumber");

void *bytes = malloc(1024);

memcpy(bytes, numero, sizeof(numero)); // sizeof(numero) == sizeof(void *)

Cela en fait un peu plus clair que ce que vous êtes annexant à l'objet NSMutableData data est les quatre premiers octets de ce que jamais numero pointe vers (qui, pour un objet en Obj-C est toujours isa, la classe d'objets ). Je soupçonne ce que vous « voulait » faire était de copier le pointeur sur l'objet instancié (la valeur de numero), auquel cas vous devriez avoir utilisé &numero. Ceci est un problème si vous utilisez GC comme le tampon utilisé par NSMutableData n'est pas scannés (le système de GC ne sera plus « voir » l'objet et le redemander, ce qui est à peu près une garantie pour un accident au hasard à un plus tard point).

Il est évident que je l'espère, même si vous mettez le pointeur sur l'objet NSNumber instancié pour data, ce pointeur n'a de sens que dans le contexte du processus qui l'a créé. Un pointeur sur cet objet est encore moins significatif si vous envoyez ce pointeur vers un autre ordinateur par ordinateur l'accueil n'a aucun moyen (pratique, trivial) pour lire la mémoire que les points de pointeur dans l'ordinateur d'envoi.

Puisque vous semblez avoir des problèmes avec cette partie du processus, permettez-moi de faire une recommandation qui vous permettra d'économiser de nombreuses heures de débogage quelques bugs de mise en œuvre extrêmement difficiles que vous êtes lié à courir pour:

Abandonner cette idée toute d'essayer d'envoyer des données binaires brutes entre les machines et simplement envoyer simplement ASCII / UTF-8 informations formatées entre eux.

Si vous pensez que cela est un peu comment va être lente ou inefficace, alors laissez-moi vous recommandons d'apporter tout en utilisant un ASCII simplifié / UTF-8 la version première de chaîne de caractères. Croyez-moi, le débogage des données binaires brutes est pas amusant, et la capacité à un peu NSLog(@"I got: %@", dataString) vaut son pesant d'or quand vous déboguez vos problèmes inévitables. Ensuite, une fois que tout a gélifié, et vous êtes sûr que vous n'avez pas besoin de faire d'autres modifications à ce que vous avez besoin d'échanger, « port » (faute d'un meilleur mot) que la mise en œuvre à une version binaire uniquement si, et seulement si , le profilage avec Shark.app identifie comme une zone de problème. En tant que point de référence, ces jours-ci, je peux scp un fichier entre les machines et saturez un lien gigabit avec le transfert. scp a probablement à faire environ cinq mille fois plus le traitement par octet pour compresser et crypter les données que ce simple tout en transférant mise en chaîne 80MB / sec. Pourtant, sur le matériel moderne, cela suffit à peine pour faire bouger le compteur CPU en marche dans ma barre de menu.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top