Frage

Ich bin auf der Suche nach einem schönen-Kakao Art und Weise eines NSData Objekt in eine hexadezimale Zeichenfolge serialisiert werden. Die Idee ist, die deviceToken verwendet zur Meldung serialisiert werden, bevor es auf meinen Server zu senden.

Ich habe die folgende Umsetzung, aber ich denke es muss etwas kürzer und schönen Weg, es zu tun.

+ (NSString*) serializeDeviceToken:(NSData*) deviceToken
{
    NSMutableString *str = [NSMutableString stringWithCapacity:64];
    int length = [deviceToken length];
    char *bytes = malloc(sizeof(char) * length);

    [deviceToken getBytes:bytes length:length];

    for (int i = 0; i < length; i++)
    {
        [str appendFormat:@"%02.2hhX", bytes[i]];
    }
    free(bytes);

    return str;
}
War es hilfreich?

Lösung

Dies ist eine Kategorie NSData angewendet, die ich geschrieben habe. Es gibt einen hexadezimalen NSString, die die NSData, wo die Daten beliebig lang sein können. Gibt eine leere Zeichenkette, wenn NSData leer ist.

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

Verbrauch:

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

Das ist „wahrscheinlich“ besser als [someData description] aufrufen und dann die Räume Strippen < 's und> s. Zeichen fühlt sich einfach zu „Hacky“ Strippen. Und Sie nie wissen, ob Apple wird die Formatierung von NSData des -description in der Zukunft ändern.

Hinweis: Ich Leute zu mir ausstrecken musste etwa in dieser Antwort für den Code Lizenzierung. Ich hiermit mein Urheberrecht im Code widme ich in dieser Antwort auf die public domain veröffentlicht.

Andere Tipps

Hier ist eine hoch optimierte NSData Kategorie Verfahren zur Herstellung eines hex-String zu erzeugen. Während @ Dave Gallagher Antwort für eine relativ geringe Größe, Speicher und CPU-Leistung verschlechtert für große Datenmengen ausreichen. Ich profilierte dies mit einem 2 MB-Datei auf meinem iPhone 5. Zeitvergleich betrug 0,05 vs 12 Sekunden. Speicherbedarf ist vernachlässigbar bei diesem Verfahren, während die andere Methode, um die Haufen zu 70MBs wuchs!

- (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));       
        if (chars == NULL) {
            // malloc returns null if attempting to allocate more memory than the system can provide. Thanks Cœur
            [NSException raise:@"NSInternalInconsistencyException" format:@"Failed to allocate more memory" arguments:nil];
            return nil;
        }
        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 @"";
}

Beschreibung Eigenschaft NSData sollte sich nicht auf einen akzeptablen Mechanismus für HEX betrachtet werden, um die Zeichenfolge codiert. Diese Eigenschaft ist für die Beschreibung nur und können sich jederzeit ändern. Als Hinweis, hat vorge iOS, die NSData Beschreibung Eigenschaft nicht einmal die Daten in Hex-Form zurück.

Es tut uns auf die Lösung Pochen aber es ist wichtig, die Energie zu nehmen, es zu serialisieren ohne Huckepack off eine API, die für etwas anderes als Datenserialisierung gemeint ist.

@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

Functional Swift Version

Motto:

let hexString = UnsafeBufferPointer<UInt8>(start: UnsafePointer(data.bytes),
count: data.length).map { String(format: "%02x", $0) }.joinWithSeparator("")

Hier ist in einer wieder verwendbaren und selbstdokumentiere Erweiterung Form:

extension NSData {
    func base16EncodedString(uppercase uppercase: Bool = false) -> String {
        let buffer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes),
                                                count: self.length)
        let hexFormat = uppercase ? "X" : "x"
        let formatString = "%02\(hexFormat)"
        let bytesAsHexStrings = buffer.map {
            String(format: formatString, $0)
        }
        return bytesAsHexStrings.joinWithSeparator("")
    }
}

Alternativ Verwendung reduce("", combine: +) statt joinWithSeparator("") als funktionellen Master von Ihren Kollegen gesehen werden.


Edit: Ich änderte String ($ 0, radix: 16) String (Format: "% 02x", 0 $), weil eine Ziffer Zahlen benötigt, um eine Polsterung Null

zu haben

Hier ist ein schneller Weg, um die Konvertierung zu tun:

BenchMark (mittlere Zeit für eine 1024 Byte Datenkonvertierung 100 mal wiederholt):

Dave Gallagher: ~ 8.070 ms
NSProgrammer: ~ 0,077 ms
Peter: ~ 0,031 ms
Diese: ~ 0,017 ms

@implementation NSData (BytesExtras)

static char _NSData_BytesConversionString_[512] = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";

-(NSString*)bytesString
{
    UInt16*  mapping = (UInt16*)_NSData_BytesConversionString_;
    register UInt16 len = self.length;
    char*    hexChars = (char*)malloc( sizeof(char) * (len*2) );

    // --- Coeur's contribution - a safe way to check the allocation
    if (hexChars == NULL) {
    // we directly raise an exception instead of using NSAssert to make sure assertion is not disabled as this is irrecoverable
        [NSException raise:@"NSInternalInconsistencyException" format:@"failed malloc" arguments:nil];
        return nil;
    }
    // ---

    register UInt16* dst = ((UInt16*)hexChars) + len-1;
    register unsigned char* src = (unsigned char*)self.bytes + len-1;

    while (len--) *dst-- = mapping[*src--];

    NSString* retVal = [[NSString alloc] initWithBytesNoCopy:hexChars length:self.length*2 encoding:NSASCIIStringEncoding freeWhenDone:YES];
#if (!__has_feature(objc_arc))
   return [retVal autorelease];
#else
    return retVal;
#endif
}

@end

Peter Antwort portiert Swift

func hexString(data:NSData)->String{
    if data.length > 0 {
        let  hexChars = Array("0123456789abcdef".utf8) as [UInt8];
        let buf = UnsafeBufferPointer<UInt8>(start: UnsafePointer(data.bytes), count: data.length);
        var output = [UInt8](count: data.length*2 + 1, repeatedValue: 0);
        var ix:Int = 0;
        for b in buf {
            let hi  = Int((b & 0xf0) >> 4);
            let low = Int(b & 0x0f);
            output[ix++] = hexChars[ hi];
            output[ix++] = hexChars[low];
        }
        let result = String.fromCString(UnsafePointer(output))!;
        return result;
    }
    return "";
}

swift3

func hexString()->String{
    if count > 0 {
        let hexChars = Array("0123456789abcdef".utf8) as [UInt8];
        return withUnsafeBytes({ (bytes:UnsafePointer<UInt8>) -> String in
            let buf = UnsafeBufferPointer<UInt8>(start: bytes, count: self.count);
            var output = [UInt8](repeating: 0, count: self.count*2 + 1);
            var ix:Int = 0;
            for b in buf {
                let hi  = Int((b & 0xf0) >> 4);
                let low = Int(b & 0x0f);
                output[ix] = hexChars[ hi];
                ix += 1;
                output[ix] = hexChars[low];
                ix += 1;
            }
            return String(cString: UnsafePointer(output));
        })
    }
    return "";
}

Swift 5

func hexString()->String{
    if count > 0 {
        let hexChars = Array("0123456789abcdef".utf8) as [UInt8];
        return withUnsafeBytes{ bytes->String in
            var output = [UInt8](repeating: 0, count: bytes.count*2 + 1);
            var ix:Int = 0;
            for b in bytes {
                let hi  = Int((b & 0xf0) >> 4);
                let low = Int(b & 0x0f);
                output[ix] = hexChars[ hi];
                ix += 1;
                output[ix] = hexChars[low];
                ix += 1;
            }
            return String(cString: UnsafePointer(output));
        }
    }
    return "";
}

Ich musste dieses Problem lösen und fand die Antworten hier sehr nützlich, aber ich mache mir Sorgen über die Leistung. Die meisten dieser Antworten beinhalten das Kopieren der Daten in loser Schüttung aus NSData so schrieb ich folgendes die Konvertierung mit geringem Overhead zu tun:

@interface NSData (HexString)
@end

@implementation NSData (HexString)

- (NSString *)hexString {
    NSMutableString *string = [NSMutableString stringWithCapacity:self.length * 3];
    [self enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop){
        for (NSUInteger offset = 0; offset < byteRange.length; ++offset) {
            uint8_t byte = ((const uint8_t *)bytes)[offset];
            if (string.length == 0)
                [string appendFormat:@"%02X", byte];
            else
                [string appendFormat:@" %02X", byte];
        }
    }];
    return string;
}

Dieser Pre-allocates Raum in der Zeichenfolge für das gesamte Ergebnis und das Kopieren verhindert jemals die NSData Inhalte aus durch enumerateByteRangesUsingBlock verwenden. Ändern des X zu einem x im Format-String wird Klein hexadezimale Ziffern verwenden. Wenn Sie nicht über ein Trennzeichen zwischen den Bytes möchten, können Sie die Anweisung reduzieren

if (string.length == 0)
    [string appendFormat:@"%02X", byte];
else
    [string appendFormat:@" %02X", byte];

auf nur

[string appendFormat:@"%02X", byte];

ich eine Antwort benötigt, die für Zeichenfolgen variabler Länge funktionieren würde, so ist hier, was ich getan habe:

+ (NSString *)stringWithHexFromData:(NSData *)data
{
    NSString *result = [[data description] stringByReplacingOccurrencesOfString:@" " withString:@""];
    result = [result substringWithRange:NSMakeRange(1, [result length] - 2)];
    return result;
}

Funktioniert hervorragend als Erweiterung für die NSString-Klasse.

Sie können jederzeit mit [Yourstring uppercaseString] Buchstaben in Datenbeschreibung nutzen

Eine bessere Art NSData in NSString zu serialisiert / deserialisiert ist die Google zu verwenden Toolbox for Mac Base64 Encoder / Decoder. Ziehen Sie einfach in Ihre App-Projekt die Dateien GTMBase64.m, GTMBase64.h e GTMDefines.h aus dem Paket-Stiftung und das so etwas wie

/**
 * Serialize NSData to Base64 encoded NSString
 */
-(void) serialize:(NSData*)data {

    self.encodedData = [GTMBase64 stringByEncodingData:data];

}

/**
 * Deserialize Base64 NSString to NSData
 */
-(NSData*) deserialize {

    return [GTMBase64 decodeString:self.encodedData];

}

Hier ist eine Lösung mit Swift 3

extension Data {

    public var hexadecimalString : String {
        var str = ""
        enumerateBytes { buffer, index, stop in
            for byte in buffer {
                str.append(String(format:"%02x",byte))
            }
        }
        return str
    }

}

extension NSData {

    public var hexadecimalString : String {
        return (self as Data).hexadecimalString
    }

}
@implementation NSData (Extn)

- (NSString *)description
{
    NSMutableString *str = [[NSMutableString alloc] init];
    const char *bytes = self.bytes;
    for (int i = 0; i < [self length]; i++) {
        [str appendFormat:@"%02hhX ", bytes[i]];
    }
    return [str autorelease];
}

@end

Now you can call NSLog(@"hex value: %@", data)

Ändern %08x %08X Hauptstadt Zeichen zu erhalten.

Swift + Property.

Ich ziehe Hex-Darstellung als Eigentum haben (die gleichen wie bytes und description Eigenschaften):

extension NSData {

    var hexString: String {

        let buffer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes), count: self.length)
        return buffer.map { String(format: "%02x", $0) }.joinWithSeparator("")
    }

    var heXString: String {

        let buffer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(self.bytes), count: self.length)
        return buffer.map { String(format: "%02X", $0) }.joinWithSeparator("")
    }
}

Idee von diesem entlehnt beantworten

[deviceToken description]

Sie müssen, um die Räume zu entfernen.

Persönlich base64 ich die deviceToken kodieren, aber es ist eine Frage des Geschmacks.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top