I've an NSData object, the length is 4 bytes .These four bytes i'm extracting from another NSData object using ,
fourByteData=[completeData subdataWithRange:NSMakeRange(0, 16)];
My first question is, will the above statement provide me the first 开发者_JAVA技巧four bytes of complete data.
If Yes, then how to convert all these bytes to an equivalent int.
Is 268566528 the value you expect or perhaps you expect 528? If the correct value is 528 then the byte order is big-endian but the cpu is little-endian, the bytes need to be reversed.
So, if the correct value should be 528 then:
NSData *data4 = [completeData subdataWithRange:NSMakeRange(0, 4)];
int value = CFSwapInt32BigToHost(*(int*)([data4 bytes]));
Also note that network standard order is big-endian.
That statement would give you the first 16 bytes of data, not 4. To get the first 4 bytes you need to modify your statement to:
fourByteData = [completeData subdataWithRange:NSMakeRange(0, 4)];
To read the data from the NSData Object to an integer you could do something like:
int theInteger;
[completeData getBytes:&theInteger length:sizeof(theInteger)];
You do not need to get the first 4 bytes if you are just converting it to an integer. You can do this directly from the two lines above and your completeData
receiver
No you will get 16 bytes of data, since the range is from offset 0 and then 16 bytes.
If you had a NSData
instance with 4 bytes then you could do a simple type cast like this:
int value = *(int*)([data bytes]);
- (unsigned)parseIntFromData:(NSData *)data{
NSString *dataDescription = [data description];
NSString *dataAsString = [dataDescription substringWithRange:NSMakeRange(1, [dataDescription length]-2)];
unsigned intData = 0;
NSScanner *scanner = [NSScanner scannerWithString:dataAsString];
[scanner scanHexInt:&intData];
return intData;
}
int numberOfChunks = [self parseIntFromData:data];
iOS integer stores LSB (lowest significant byte) in the first byte and MSB in the last byte. I have conversion routine to test all those things. check here,
Test ...
int i = 2342342;
NSData * d1 = [Util dataFromInt:i]; // {[MSB], ..., ... ,[LSB]} <0023bdc6>
NSData * d2 = [NSData dataWithBytes:&i length:4]; // {[LSB], ..., ... ,[MSB]} <c6bd2300>
int ci1 = [Util intFromData:d1];
int ci2 = [Util intFromDataReverse:d2];
Util.m
+ (NSData *) dataFromInt:(int)num {
unsigned char * arr = (unsigned char *) malloc(sizeof(num) * sizeof(unsigned char));
for (int i = sizeof(num) - 1 ; i >= 0; i --) {
arr[i] = num & 0xFF;
num = num >> 8;
}
NSData * data = [NSData dataWithBytes:arr length:sizeof(num)];
free(arr);
return data;
}
// {[MSB], ..., ... ,[LSB]}
+ (int) intFromData:(NSData *)data
{
int intSize = sizeof(int); // change it to fixe length
unsigned char * buffer = malloc(intSize * sizeof(unsigned char));
[data getBytes:buffer length:intSize];
int num = 0;
for (int i = 0; i < intSize; i++) {
num = (num << 8) + buffer[i];
}
free(buffer);
return num;
}
// {[LSB], ..., ... ,[MSB]}
+ (int) intFromDataReverse:(NSData *)data
{
int intSize = sizeof(int);// change it to fixe length
unsigned char * buffer = malloc(intSize * sizeof(unsigned char));
[data getBytes:buffer length:intSize];
int num = 0;
for (int i = intSize - 1; i >= 0; i--) {
num = (num << 8) + buffer[i];
}
free(buffer);
return num;
}
It depends on the Endianness notation of the data you want to convert, in relation to your device Endianness notation. wiki on Endianness
To keep it simple you need to check does two method
NSData *data4 = [completeData subdataWithRange:NSMakeRange(0, 4)];
int value = CFSwapInt32BigToHost(*(int*)([data4 bytes]));
or
NSData *data4 = [completeData subdataWithRange:NSMakeRange(0, 4)];
int value = CFSwapInt32LittleToHost(*(int*)([data4 bytes]));
And check which one make more sense when you parse the data.
Assuming _vertexData
is NSData
here
and you know what data (types) to expect in your buffer you can iterate thru this block with NSData's .length
property.
In this Example each data block was 32 Bytes (storing 8 x float values) and i was interested in logging starting at the 5th float value
float a,b,c,d; //prepare some values, no need to initialize
// loop thru assuming 8 floats are stored after each other
for (NSUInteger v = 0; v < _vertexData.length; v += sizeof(float)*8 ) {
// set a starting point for the range, here the 5th float
NSUInteger shift = v + (sizeof(float)*4);
// store result in a..
[_vertexData getBytes:&a range:NSMakeRange(shift,sizeof(a))];
// increase the starting point by the size of data before
shift += sizeof(a);
[_vertexData getBytes:&b range:NSMakeRange(shift,sizeof(b))];
shift += sizeof(b);
[_vertexData getBytes:&c range:NSMakeRange(shift,sizeof(c))];
shift += sizeof(c);
[_vertexData getBytes:&d range:NSMakeRange(shift,sizeof(d))];
fprintf(stderr, "r%f, g%f, b%f, a%f \n", a,b,c,d );
}
this could have been written much shorter, but for the sake of clarity and with less use of miss leading castings
maybe this helps someone
精彩评论