2009-11-05 5 views
3

Je suis assez nouveau à Objective-C (et C lui-même) et besoin de consommer un NSData à partir d'une sortie HTTP. Je n'ai jamais vraiment travaillé avec des tableaux d'octets ou je devais m'inquiéter de problèmes petits/gros, et j'ai eu du mal à écrire la méthode suivante pour lire un NSNumber avec une longueur spécifiée de NSData.Lire NSNumber de NSData

- (NSNumber *)readNumberWithLength:(NSUInteger)length 
{ 
    Byte k[length]; 
    [data getBytes:k range:NSMakeRange(offset, length)]; // big endian byte array representing a number 
    offset += length; 

    NSNumber *number; 
    if (length==4) { 
     number = [NSNumber numberWithUnsignedInt:CFSwapInt32BigToHost(*(uint32_t *)k)]; 
    } else if (length==2) { 
     number = [NSNumber numberWithUnsignedShort:CFSwapInt16BigToHost(*(uint16_t *)k)]; 
    } else if (length==1) { 
     number = [NSNumber numberWithUnsignedChar:*(uint8_t *)k]; 
    } else if (length==8) { 
     number = [NSNumber numberWithUnsignedLongLong:CFSwapInt64BigToHost(*(uint64_t *)k)]; 
    } else { 
     number = [NSNumber numberWithInt:0]; 
    } 

    return number; 
} 

Je NSData *data et NSUInteger offset a déclaré que les variables d'instance.

Ce code est-il correct? Y a-t-il quelque chose dont je devrais me soucier? Je ne l'ai pas encore testé sur un appareil réel (uniquement sur le simulateur) et cela semble fonctionner correctement pour moi. Avez-vous des commentaires à ce sujet?

Merci!

Répondre

2

Le code semble plus ou moins correct.

On dirait que c'est difficile.

Je serais surpris - pas totalement choqué, mais surpris - que les données provenant du serveur HTTP ne soient en réalité que des octets bruts. Il serait exceptionnellement rare que ce soit le cas et, dans le cas où c'est le cas, la conception du serveur est presque assurément fausse. (Il y a certainement des cas où la réponse binaire-HTTP est la bonne réponse, mais c'est très très rare). À moins que vous ne parliez de centaines de milliers de valeurs dans les données, le surcoût implicite de HTTP va presque certainement l'emporter sur les gains de binaire. L'analyse des valeurs numériques connues à partir d'une chaîne n'est pas que onéreuse, sauf si vous faites vraiment cela constamment (ce qui rendrait l'utilisation de HTTP pas particulièrement attrayant en premier lieu).


Conception du serveur: assez juste. Une autre raison valable de traiter est parce que vous ne pouvez pas changer cette pièce particulière du puzzle.

je mettre en œuvre personnellement le code plus défensivement:

  • valident que les tailles de données locales sont des tailles attendues par rapport aux tailles à distance/réseau pour éviter des surprises (cela pourrait être des affirmations sur l'initialisation ou dans un peu de code de débogage - je préfère être über défensif dans des situations comme celles-ci).

  • utilisez une instruction case au lieu de la séquence if/else if/else if/else. Complètement une décision esthétique, mais il contribuerait à ...

  • ... traitent le length étant une valeur inattendue en se connectant, même si seulement en mode debug. Je pense qu'une taille de valeur inattendue serait potentiellement très mauvaise pour l'exactitude globale?

+0

Il s'agit d'une API RESTful qui répond vraiment aux collections avec des centaines de valeurs (chaînes et nombres). La sortie est gzipée, donc ça a du sens pour moi. Je n'ai pas vraiment conçu le serveur et ça ne va pas changer, donc je suis plus inquiet que si ma mise en œuvre est correcte. Pensez-vous qu'il existe une meilleure façon de faire cela? Merci! – leolobato

+0

Merci pour les conseils! J'étais en fait préoccupé par la façon dont je faisais la conversion du tableau d'octets en nsnumber, mais puisque vous n'avez pas mentionné cette partie, on dirait que c'est correct (ou du moins un moyen valable). :) – leolobato