Take the 2-minute tour ×

When I call -description on an NSData object, I see a pretty Hex string of the NSData object's bytes like:

<f6e7cd28 0fc5b5d4 88f8394b af216506 bc1bba86 4d5b483d>

I'd like to get this representation of the data (minus the lt/gt quotes) into an in-memory NSString so I can work with it.. I'd prefer not to call -[NSData description] and then just trim the lt/gt quotes (because I assume that is not a guaranteed aspect of NSData's public interface and is subject change in the future).

What's the simplest way to get this representation of an NSData object into an NSString object (other than calling -description)?

share|improve this question
So, why not description? (Really curious. Suspect I'll learn something.) –  Steven Fisher Sep 22 '11 at 19:57
@Steven: description's output may change across system versions. For example, -[NSDate description] was, pre-Lion, documented as returning a string with exactly the same format as was required for -[NSDate initWithString:]; that guarantee is no longer made. Brief discussion here: stackoverflow.com/questions/5837777/… –  Josh Caswell Sep 22 '11 at 20:12
description should be used for debugging purposes only, because you have no guaranty that the value returned by the description method won't change in future releases (even if it is unlikely). For example nothing tells your that Apple won't decide some day that if [NSData length]>200, then the string returned by description will be clipped in the middle... or anything similar. So this is why its may not be a good practice to rely on what is returned by description for anything else than debugging/logging. –  AliSoftware Sep 22 '11 at 20:17
Makes sense. Thanks. I have to admit, I've provided custom descriptions for my own debugging purposes. –  Steven Fisher Sep 23 '11 at 4:05
add comment

6 Answers

up vote 19 down vote accepted

I agree on the solution not to call description which is to be reserved for debugging, so good point and good question :)

The easiest solution is to loop thru the bytes of the NSData and construct the NSString from it. Use [yourData bytes] to access the bytes, and build the string into an NSMutableString.

Here is an example by implementing this using a category of NSData

@interface NSData(Hex)

@implementation NSData(Hex)
    const unsigned char* bytes = (const unsigned char*)[self bytes];
    NSUInteger nbBytes = [self length];
    //If spaces is true, insert a space every this many input bytes (twice this many output characters).
    static const NSUInteger spaceEveryThisManyBytes = 4UL;
    //If spaces is true, insert a line-break instead of a space every this many spaces.
    static const NSUInteger lineBreakEveryThisManySpaces = 4UL;
    const NSUInteger lineBreakEveryThisManyBytes = spaceEveryThisManyBytes * lineBreakEveryThisManySpaces;
    NSUInteger strLen = 2*nbBytes + (spaces ? nbBytes/spaceEveryThisManyBytes : 0);

    NSMutableString* hex = [[NSMutableString alloc] initWithCapacity:strLen];
    for(NSUInteger i=0; i<nbBytes; ) {
        [hex appendFormat:@"%02X", bytes[i]];
        //We need to increment here so that the every-n-bytes computations are right.

        if (spaces) {
            if (i % lineBreakEveryThisManyBytes == 0) [hex appendString:@"\n"];
            else if (i % spaceEveryThisManyBytes == 0) [hex appendString:@" "];
    return [hex autorelease];


NSData* data = ...
NSString* hex = [data hexRepresentationWithSpaces_AS:YES];
share|improve this answer
Except that you’re not actually formatting the original bytes into the returned string. –  Bavarious Sep 22 '11 at 20:17
Errr can you explain your comment? –  AliSoftware Sep 22 '11 at 20:20
In [hex appendFormat:@"%02X"], you’re supposed to pass another argument telling what data should be formatted with the format specifier — in this case, data pointed by the bytes variable offset according to the loop. –  Bavarious Sep 22 '11 at 20:22
Oh, right, nice catch, just forgot it! (Didn't try my code actually, haven't my mac with me right now). Thx, I edited my answer accordingly:) –  AliSoftware Sep 22 '11 at 20:23
Nitpick: If you want to match description you'd want "%02x", rather than "%02X". (The difference is lowercase vs. uppercase.) –  Steven Fisher Sep 23 '11 at 4:09
show 1 more comment
NSData *data = ...;
NSUInteger capacity = [data length] * 2;
NSMutableString *stringBuffer = [NSMutableString stringWithCapacity:capacity];
const unsigned char *dataBuffer = [data bytes];
NSInteger i;
for (i=0; i<[data length]; ++i) {
  [stringBuffer appendFormat:@"%02X", (NSUInteger)dataBuffer[i]];
share|improve this answer
2 years later, this answer just saved my ass. Thanks bud –  John Jul 17 '13 at 21:36
add comment

I liked @Erik_Aigner's answer the best. I just refactored it a bit:

NSData *data = [NSMutableData dataWithBytes:"acani" length:5];
NSUInteger dataLength = [data length];
NSMutableString *string = [NSMutableString stringWithCapacity:dataLength*2];
const unsigned char *dataBytes = [data bytes];
for (NSInteger idx = 0; idx < dataLength; ++idx) {
    [string appendFormat:@"%02x", dataBytes[idx]];
share|improve this answer
add comment

Sadly there's no built-in way to produce hex from an NSData, but it's pretty easy to do yourself. The simple way is to just pass successive bytes into sprintf("%02x") and accumulate those into an NSMutableString. A faster way would be to build a lookup table that maps 4 bits into a hex character, and then pass successive nybbles into that table.

share|improve this answer
No need to use sprintf; NSMutableString has appendFormat:. –  Peter Hosey Sep 23 '11 at 1:52
add comment

I wrote an NSData to hexadecimal NSString category you can find here: http://stackoverflow.com/a/9084784/153040

It's similar to AliSoftware's answer.

share|improve this answer
add comment

While it may not be the most efficient way to do it, if you're doing this for debugging, SSCrypto has a category on NSData which contains two methods to do this (one for creating an NSString of the raw byte values, and one which shows a prettier representation of it).


share|improve this answer
add comment

Your Answer


