Jest to kategoria dotycząca NSData, którą napisałem. Zwraca szesnastkowy NSString reprezentujący NSData, gdzie dane mogą mieć dowolną długość. Zwraca pusty ciąg, jeśli NSData jest pusty.
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
Stosowanie:
NSData *someData = ...;
NSString *someDataHexadecimalString = [someData hexadecimalString];
Jest to „prawdopodobnie” lepsze niż wywołanie, [someData description]
a następnie usunięcie spacji, <i>. Usuwanie postaci wydaje się po prostu zbyt „hackowe”. Poza tym nigdy nie wiadomo, czy Apple zmieni -description
w przyszłości formatowanie NSData .
UWAGA: Wiele osób skontaktowało się ze mną w sprawie licencji na kod w tej odpowiedzi. Niniejszym dedykuję moje prawa autorskie do kodu, który zamieściłem w tej odpowiedzi, do domeny publicznej.
"%02lx"
z tym rzutowaniem,(unsigned int)
@"%02hhx"
[hexString appendFormat:@"%02x", (unsigned int)dataBuffer[i]];
jest znacznie lepszy (mniejszy ślad pamięci)Oto wysoce zoptymalizowana metoda kategorii NSData do generowania ciągu szesnastkowego. Chociaż odpowiedź @Dave'a Gallaghera jest wystarczająca dla stosunkowo małego rozmiaru, wydajność pamięci i procesora pogarsza się w przypadku dużych ilości danych. Profilowałem to za pomocą pliku o wielkości 2 MB na moim iPhonie 5. Porównanie czasu wyniosło 0,05 do 12 sekund. Wykorzystanie pamięci jest znikome w przypadku tej metody, podczas gdy inna metoda zwiększyła stertę do 70 MB!
źródło
Używanie właściwości description NSData nie powinno być uważane za akceptowalny mechanizm kodowania HEX łańcucha. Ta właściwość służy wyłącznie do opisu i może ulec zmianie w dowolnym momencie. Uwaga: przed iOS właściwość opisu NSData nawet nie zwracała danych w postaci szesnastkowej.
Przepraszamy za nękanie rozwiązania, ale ważne jest, aby wziąć energię do serializacji bez wycofywania interfejsu API, który jest przeznaczony do czegoś innego niż serializacja danych.
źródło
description
zwraca ciąg zakodowany szesnastkowo, więc wydaje mi się to rozsądne.Oto szybszy sposób wykonania konwersji:
BenchMark (średni czas konwersji danych 1024 bajty powtórzony 100 razy):
Dave Gallagher: ~
8,070 ms NSP Programmer: ~ 0,077 ms
Peter: ~ 0,031 ms
Ten: ~ 0,017 ms
źródło
_hexString
metoda): github.com/ZipArchive/ZipArchive/blob/master/SSZipArchive/ ...Funkcjonalna wersja Swift
Jedna wkładka:
Oto rozszerzenie do wielokrotnego użytku, samodokumentujące się:
Alternatywnie, użyj
reduce("", combine: +)
zamiastjoinWithSeparator("")
być postrzeganym przez swoich rówieśników jako wzorzec funkcjonalny.Edycja: Zmieniłem String (0 $, podstawa: 16) na String (format: "% 02x", $ 0), ponieważ liczby jednocyfrowe potrzebne do wypełnienia zerem
źródło
Odpowiedź Petera została przeniesiona do Szybkiego
swift3
Szybki 5
źródło
Musiałem rozwiązać ten problem i znalazłem tutaj bardzo przydatne odpowiedzi, ale martwię się o wydajność. Większość z tych odpowiedzi obejmuje zbiorcze kopiowanie danych z NSData, więc napisałem co następuje, aby wykonać konwersję z niskim narzutem:
To wstępnie przydziela miejsce w ciągu dla całego wyniku i zapobiega kopiowaniu zawartości NSData przy użyciu enumerateByteRangesUsingBlock. Zmiana X na x w ciągu formatu spowoduje użycie małych cyfr szesnastkowych. Jeśli nie chcesz separatora między bajtami, możesz zmniejszyć instrukcję
do sprawiedliwego
źródło
NSRange
wskazuje zakres w większejNSData
reprezentacji, a nie w buforze o mniejszych bajtach (ten pierwszy parametr bloku dostarczonego doenumerateByteRangesUsingBlock
), który reprezentuje pojedynczą ciągłą część większegoNSData
. W ten sposóbbyteRange.length
odzwierciedla rozmiar bufora bajtów, alebyteRange.location
jest to lokalizacja w większymNSData
. Dlatego chcesz użyć po prostuoffset
, a niebyteRange.location + offset
, aby pobrać bajt.appendFormat
należy prawdopodobnie również zmianęself.length * 3
doself.length * 2
Potrzebowałem odpowiedzi, która działałaby dla ciągów o zmiennej długości, więc oto co zrobiłem:
Świetnie sprawdza się jako rozszerzenie klasy NSString.
źródło
Zawsze możesz użyć [yourString uppercaseString], aby użyć wielkich liter w opisie danych
źródło
Lepszym sposobem serializacji / deserializacji NSData do NSString jest użycie programu Google Toolbox for Mac Base64 kodera / dekodera. Po prostu przeciągnij do projektu aplikacji pliki GTMBase64.m, GTMBase64.he GTMDefines.h z pakietu Foundation i wykonaj coś w rodzaju
źródło
string = [data base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0]
Oto rozwiązanie wykorzystujące Swift 3
źródło
źródło
Zmień
%08x
na,%08X
aby uzyskać duże znaki.źródło
Swift + Property.
Wolę mieć reprezentację szesnastkową jako właściwość (taką samą jak
bytes
idescription
właściwości):Pomysł jest zapożyczony z tej odpowiedzi
źródło
Musisz usunąć spacje.
Osobiście
base64
kodujędeviceToken
, ale to kwestia gustu.źródło