C'est une catégorie appliquée à NSData que j'ai écrite. Elle renvoie une NSString hexadécimale représentant le NSData, où les données peuvent être de n'importe quelle longueur. Renvoie une chaîne vide si NSData est vide.
NSData + Conversion.h
#import <Foundation/Foundation.h>
@interface NSData (NSData_Conversion)
#pragma mark - String Conversion
- (NSString *)hexadecimalString;
@end
NSData + 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
Usage:
NSData *someData = ...;
NSString *someDataHexadecimalString = [someData hexadecimalString];
C'est "probablement" mieux que d'appeler [someData description]
puis de supprimer les espaces, <et>. Décapage des personnages semble trop "hacky". De plus, vous ne savez jamais si Apple modifiera le formatage des NSData -description
à l'avenir.
REMARQUE: des personnes m'ont contacté au sujet de la licence pour le code dans cette réponse. Par la présente, je dédie mes droits d'auteur sur le code que j'ai publié dans cette réponse au domaine public.
"%02lx"
avec ce casting, ou cast vers(unsigned int)
, ou abandonner le casting et utiliser@"%02hhx"
:)[hexString appendFormat:@"%02x", (unsigned int)dataBuffer[i]];
est beaucoup mieux (empreinte mémoire plus petite)Voici une méthode de catégorie NSData hautement optimisée pour générer une chaîne hexadécimale. Alors que la réponse de @Dave Gallagher est suffisante pour une taille relativement petite, les performances de la mémoire et du processeur se détériorent pour de grandes quantités de données. J'ai profilé cela avec un fichier de 2 Mo sur mon iPhone 5. La comparaison de temps était de 0,05 vs 12 secondes. L'empreinte mémoire est négligeable avec cette méthode tandis que l'autre méthode a augmenté le tas à 70 Mo!
la source
L'utilisation de la propriété description de NSData ne doit pas être considérée comme un mécanisme acceptable pour le codage HEX de la chaîne. Cette propriété n'est fournie qu'à titre indicatif et peut changer à tout moment. À noter, avant iOS, la propriété de description NSData ne retournait même pas ses données sous forme hexadécimale.
Désolé de parler de la solution, mais il est important de prendre l'énergie nécessaire pour la sérialiser sans utiliser une API destinée à autre chose que la sérialisation des données.
la source
description
renvoie une chaîne codée en hexadécimal, donc cela me semble raisonnable.Voici un moyen plus rapide d'effectuer la conversion:
BenchMark (temps moyen pour une conversion de données de 1024 octets répétée 100 fois):
Dave Gallagher: ~ 8,070 ms
NSProgrammer: ~ 0,077 ms
Peter: ~ 0,031 ms
Celui-ci: ~ 0,017 ms
la source
_hexString
méthode): github.com/ZipArchive/ZipArchive/blob/master/SSZipArchiveVersion Swift fonctionnelle
Bon mot:
Voici sous une forme d'extension réutilisable et auto-documentée:
Vous pouvez également utiliser
reduce("", combine: +)
au lieu dejoinWithSeparator("")
pour être considéré comme un maître fonctionnel par vos pairs.Edit: J'ai changé String ($ 0, radix: 16) en String (format: "% 02x", $ 0), car les nombres à un chiffre devaient avoir un zéro de remplissage
la source
La réponse de Peter portée sur Swift
swift3
Swift 5
la source
J'avais besoin de résoudre ce problème et j'ai trouvé les réponses ici très utiles, mais je m'inquiète des performances. La plupart de ces réponses impliquent de copier les données en vrac hors de NSData, j'ai donc écrit ce qui suit pour effectuer la conversion avec une faible surcharge:
Cela pré-alloue de l'espace dans la chaîne pour l'ensemble du résultat et évite de copier le contenu NSData à l'aide de enumerateByteRangesUsingBlock. Changer le X en x dans la chaîne de format utilisera des chiffres hexadécimaux minuscules. Si vous ne voulez pas de séparateur entre les octets, vous pouvez réduire l'instruction
jusqu'à juste
la source
NSRange
indique la plage dans la plus grandeNSData
représentation, pas dans le tampon d'octets plus petit (ce premier paramètre du bloc fourni àenumerateByteRangesUsingBlock
) qui représente une seule partie contiguë du plus grandNSData
. Ainsi,byteRange.length
reflète la taille du tampon d'octets, maisbyteRange.location
est l'emplacement dans le plus grandNSData
. Ainsi, vous souhaitez utiliser simplementoffset
, nonbyteRange.location + offset
, pour récupérer l'octet.appendFormat
vous devriez probablement également changer leself.length * 3
enself.length * 2
J'avais besoin d'une réponse qui fonctionnerait pour des chaînes de longueur variable, alors voici ce que j'ai fait:
Fonctionne très bien comme extension de la classe NSString.
la source
Vous pouvez toujours utiliser [yourString uppercaseString] pour mettre des lettres en majuscule dans la description des données
la source
Un meilleur moyen de sérialiser / désérialiser NSData dans NSString consiste à utiliser l' encodeur / décodeur Google Toolbox pour Mac Base64. Faites simplement glisser dans votre projet d'application les fichiers GTMBase64.m, GTMBase64.he GTMDefines.h du package Foundation et faites quelque chose comme
la source
string = [data base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0]
Voici une solution utilisant Swift 3
la source
la source
Remplacez
%08x
par%08X
pour obtenir des caractères majuscules.la source
Swift + Propriété.
Je préfère avoir une représentation hexadécimale comme propriété (la même chose que
bytes
etdescription
properties):L'idée est empruntée à cette réponse
la source
Vous devrez supprimer les espaces.
Personnellement
base64
j'encode ledeviceToken
, mais c'est une question de goût.la source