103 votes

Meilleure façon de sérialiser un NSData dans une chaîne de hexadeximal

Je cherche un moyen agréable-cacao sérialiser un objet NSData dans une chaîne hexadécimale. L’idée est de sérialiser le deviceToken utilisée pour la notification avant de l’envoyer à mon serveur.

J’ai l’implémentation suivante, mais je pense qu’il doit y avoir quelque moyen plus court et plus agréable de le faire.

Merci pour vos contributions.

Thomas

209voto

Dave Gallagher Points 5314

C'est une catégorie à NSData que j'ai écrit. Elle retourne la valeur hexadécimale NSString représentant le NSData, où les données peuvent être n'importe quelle longueur. Retourne une chaîne vide si NSData est vide.

NSData+De Conversion.h

#import <Foundation/Foundation.h>

@interface NSData (NSData_Conversion)

#pragma mark - String Conversion
- (NSString *)hexadecimalString;

@end

NSData+De Conversion.m

#import "NSData+Conversion.h"

@implementation NSData (NSData_Conversion)

#pragma mark - String Conversion
- (NSString *)hexadecimalString {
    /* Returns hexadecimal string of NSData. Empty string if data is empty.   */

    const unsigned char *dataBuffer = (const unsigned char *)[self bytes];

    if (!dataBuffer)
        return [NSString string];

    NSUInteger          dataLength  = [self length];
    NSMutableString     *hexString  = [NSMutableString stringWithCapacity:(dataLength * 2)];

    for (int i = 0; i < dataLength; ++i)
        [hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];

    return [NSString stringWithString:hexString];
}

@end

Utilisation:

NSData *someData = ...;
NSString *someDataHexadecimalString = [someData hexadecimalString];

Ce est "probablement" de mieux que d'appeler [someData description] puis de décapage les espaces, <'s, et s>'. Le décapage de caractères se sent juste trop "hacky". De Plus, vous ne savez jamais si Apple va modifier la mise en forme de NSData de l' -description dans le futur.

32voto

Peter Points 101

Voici un très optimisé NSData catégorie méthode pour générer une chaîne hexadécimale. Alors que @Dave Gallagher réponse est suffisante pour une taille relativement petite, la mémoire et les performances du processeur se détériorer pour les grandes quantités de données. Je profilé avec un fichier de 2 mo sur mon iPhone 5. Comparaison du temps a été de 0,05 vs 12 secondes. Empreinte mémoire est négligeable avec cette méthode, tandis que l'autre méthode a grandi un tas de 70MBs! Crédit à PMUtils.

- (NSString *) hexString
{
    NSUInteger bytesCount = self.length;
    if (bytesCount) {
        const char *hexChars = "0123456789ABCDEF";
        const unsigned char *dataBuffer = self.bytes;
        char *chars = malloc(sizeof(char) * (bytesCount * 2 + 1));
        char *s = chars;
        for (unsigned i = 0; i < bytesCount; ++i) {
            *s++ = hexChars[((*dataBuffer & 0xF0) >> 4)];
            *s++ = hexChars[(*dataBuffer & 0x0F)];
            dataBuffer++;
        }
        *s = '\0';
        NSString *hexString = [NSString stringWithUTF8String:chars];
        free(chars);
        return hexString;
    }
    return @"";
}

17voto

NSProgrammer Points 1210

À l'aide de la propriété description de NSData ne doit pas être considéré comme un mécanisme acceptable pour le codage HEXADÉCIMAL de la chaîne. Cette propriété est pour la description seulement et peuvent changer à tout moment. Comme une note, pré-iOS, le NSData description de la propriété n'a pas encore de retour des données en format hexadecimal.

Désolé pour revenir sur la solution, mais il est important de prendre l'énergie pour sérialiser sans piggy-backing hors d'une API qui est destiné à quelque chose d'autre que de sérialisation des données.

@implementation NSData (Hex)
- (NSString*)hexString {
    NSUInteger length = self.length;
    unichar* hexChars = (unichar*)malloc(sizeof(unichar) * (length*2));
    unsigned char* bytes = (unsigned char*)self.bytes;
    for (NSUInteger i = 0; i < length; i++) {
        unichar c = bytes[i] / 16;
        if (c < 10) c += '0';
        else c += 'A' - 10;
        hexChars[i*2] = c;
        c = bytes[i] % 16;
        if (c < 10) c += '0';
        else c += 'A' - 10;
        hexChars[i*2+1] = c;
    }
    NSString* retVal = [[NSString alloc] initWithCharactersNoCopy:hexChars
                                                           length:length*2 
                                                     freeWhenDone:YES];
    return [retVal autorelease];
}
@end

16voto

ianolito Points 1738

Qu'en est-il de :

1voto

BadPirate Points 11614

J’avais besoin une réponse qui pourrait fonctionner pour les chaînes de longueur variable, donc voici ce que j’ai fait :

Fonctionne très bien comme une extension pour la classe NSString.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X