51

I want to convert NSData to a byte array, so I write the following code:

NSData *data = [NSData dataWithContentsOfFile:filePath];
int len = [data length];
Byte byteData[len];
byteData = [data bytes];

But the last line of code pops up an error saying "incompatible types in assignment". What is the correct way to convert the data to byte array then?

Yi Jiang
  • 49,435
  • 16
  • 136
  • 136
Chilly Zhong
  • 16,763
  • 23
  • 77
  • 103

6 Answers6

63

You can't declare an array using a variable so Byte byteData[len]; won't work. If you want to copy the data from a pointer, you also need to memcpy (which will go through the data pointed to by the pointer and copy each byte up to a specified length).

Try:

NSData *data = [NSData dataWithContentsOfFile:filePath];
NSUInteger len = [data length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);

This code will dynamically allocate the array to the correct size (you must free(byteData) when you're done) and copy the bytes into it.

You could also use getBytes:length: as indicated by others if you want to use a fixed length array. This avoids malloc/free but is less extensible and more prone to buffer overflow issues so I rarely ever use it.

Matt Gallagher
  • 14,858
  • 2
  • 41
  • 43
43

You could also just use the bytes where they are, casting them to the type you need.

unsigned char *bytePtr = (unsigned char *)[data bytes];
stevex
  • 5,589
  • 37
  • 52
16

Already answered, but to generalize to help other readers:

    //Here:   NSData * fileData;
    uint8_t * bytePtr = (uint8_t  * )[fileData bytes];

    // Here, For getting individual bytes from fileData, uint8_t is used.
    // You may choose any other data type per your need, eg. uint16, int32, char, uchar, ... .
    // Make sure, fileData has atleast number of bytes that a single byte chunk would need. eg. for int32, fileData length must be > 4 bytes. Makes sense ?

    // Now, if you want to access whole data (fileData) as an array of uint8_t
    NSInteger totalData = [fileData length] / sizeof(uint8_t);

    for (int i = 0 ; i < totalData; i ++)
    {
        NSLog(@"data byte chunk : %x", bytePtr[i]);
    }
Khulja Sim Sim
  • 3,469
  • 1
  • 29
  • 28
10

The signature of -[NSData bytes] is - (const void *)bytes. You can't assign a pointer to an array on the stack. If you want to copy the buffer managed by the NSData object into the array, use -[NSData getBytes:]. If you want to do it without copying, then don't allocate an array; just declare a pointer variable and let NSData manage the memory for you.

Nicholas Riley
  • 43,532
  • 6
  • 101
  • 124
2

That's because the return type for [data bytes] is a void* c-style array, not a Uint8 (which is what Byte is a typedef for).

The error is because you are trying to set an allocated array when the return is a pointer type, what you are looking for is the getBytes:length: call which would look like:

[data getBytes:&byteData length:len];

Which fills the array you have allocated with data from the NSData object.

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
-1

Here's what I believe is the Swift equivalent:

if let data = NSData(contentsOfFile: filePath) {
   let length = data.length
   let byteData = malloc(length)
   memcmp(byteData, data.bytes, length)
}
jervine10
  • 3,039
  • 22
  • 35