This question already has an answer here:
NSMutableData datawithBytesNoCopy:length:freeWhenDone: seems to make a copy of the buffer provided to it
(1 answer)
Closed 8 years ago.
I am trying to write a code to create NSMutableData from malloced buffer.I used freewhendone = YES
1) It gives an error in accessing the buffer after NSData is created.(in memset in below code)
2) The malloced buffer pointer and [data bytes] pointer are different.
Is there any explanation for these?
UWORD8 *rgb_buffer = malloc(u4_stride * u4_height * 3);
NSMutableData *rgbData = [NSMutableData dataWithBytesNoCopy:rgb_buffer
length:(u4_stride * u4_height * 3)
freeWhenDone:YES];
memset(rgb_buffer, 0, (u4_stride * u4_height * 3));
From Binary Data Programming Guide
NSMutableData responds to dataWithBytesNoCopy:length:, but the bytes are copied
anyway and the buffer is freed immediately.
It gives an error in accessing the buffer after NSData is created.(in memset in below code)
buffer is freed immediately.
The malloced buffer pointer and [data bytes] pointer are different.
NSMutableData create copy of bytes.
Related
There's a special NSString initWithData method for grabbing bits and converting them into string. However, I haven't found that in NSNumber class ref. Currently, I'm getting raw data (bytes) from a server in NSData format. I know how to do that in C, using memcpy and int pointers. But I am curious about what the convenience methods are for doing that straight from NSData. No conversion is needed. For example, I'm getting 00000010 byte, and I need to turn that into NSNumber of value 2, or NSInteger.
NSData is just a bucket for bytes and has no knowledge of the data contained therein. NSString's initWithData:encoding: method is a reciprocal (it does the opposite) of this method:
- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
Therefore, to answer your question fully, it's important to know how your numbers were originally coerced into an NSData object. Once you know the encoding function, the search is for the reciprocal function.
From what you've included in the question, there may be a number of different solutions. However, you'll probably be able to use something along the following lines to convert into a usable numeric format using getBytes:length: on your NSData object. For e.g.
NSUInteger decodedInteger;
[myDataObject getBytes:&decodedInteger length:sizeof(decodedInteger)];
You can change the type of decodedInteger to whatever is appropriate for the bytes in your NSData object.
Try this:
NSNumber *num = [NSKeyedUnarchiver unarchiveObjectWithData:numberAsNSData];
Edit:
As pointed out by Matthias Bauch this will not work in your case. This only works if your NSNumber object was archived into NSData objects.
NSString to the rescue:
const unsigned char *bytes = [serverData bytes];
NSInteger aValue = [NSString stringWithFormat:#"%2x", bytes[0]].integerValue;
The docs warn about using NSScanner for localized decimal numbers, but that's of no concern in this case.
Here is the answer
//Integer to NSData
+(NSData *) IntToNSData:(NSInteger)data
{
Byte *byteData = (Byte*)malloc(4);
byteData[3] = data & 0xff;
byteData[2] = (data & 0xff00) >> 8;
byteData[1] = (data & 0xff0000) >> 16;
byteData[0] = (data & 0xff000000) >> 24;
NSData * result = [NSData dataWithBytes:byteData length:4];
NSLog(#"result=%#",result);
return (NSData*)result;
}
refer https://stackoverflow.com/a/20497490/562812 for more detail
Are there any built in utilities or macros in the objective-c libraries for iOS that will allow you to convert bytes to and from integers with respect to endianess?
Please don't tell me to use bit-shifting operations. I am trying to avoid writing custom code to do this if it already exists.
I would like the code to convert NSData* to primitive types (int, uint, short, etc) and to convert primitive types back to NSData*.
You can get the bytes from NSData by accessing the bytes property. Then just cast that to a pointer to whatever type you want. Obviously you'll need to ensure you know the endianness and size of what is in your NSData.
e.g.
#include <CFByteOrder.h>
// Bytes to uint32_t
NSData *data = <THE_DATA>;
void *bytes = [data bytes];
uint32_t *intBytes = (NSInteger*)bytes;
uint32_t swapped = CFSwapInt32BigToHost(*intBytes); ///< If the data in `data' is big endian
// uint32_t to bytes
uint32_t someInt = 1234;
uint32_t swappedInt = CFSwapInt32HostToBig(someInt); ///< If we want to store in big endian
NSData *data = [NSData dataWithBytes:&swappedInt length:sizeof(swappedInt)];
I think you want the CFSwapInt32* family of functions.
See Apple's docs.
I have an NSData object of approximately 1000kB in size. Now I want to transfer this via Bluetooth. It would be better if I have, let's say, 10 objects of 100kB. It comes to mind that I should use the -subdataWithRange: method of NSData.
I haven't really worked with NSRange. Well, I know how it works, but I can't figure out how to read from a given location with the length: 'to end of file'... I've no idea how to do that.
Some code on how to split this into multiple 100kB NSData objects would really help me out here. (it probably involves the -length method to see how many objects should be made..?)
Thank you in advance.
The following piece of code does the fragmentation without copying the data:
NSData* myBlob;
NSUInteger length = [myBlob length];
NSUInteger chunkSize = 100 * 1024;
NSUInteger offset = 0;
do {
NSUInteger thisChunkSize = length - offset > chunkSize ? chunkSize : length - offset;
NSData* chunk = [NSData dataWithBytesNoCopy:(char *)[myBlob bytes] + offset
length:thisChunkSize
freeWhenDone:NO];
offset += thisChunkSize;
// do something with chunk
} while (offset < length);
Sidenote: I should add that the chunk objects cannot safely be used after myBlob has been released (or otherwise modified). chunk fragments point into memory owned by myBlob, so don't retain them unless you retain myBlob.
Can someone help me ? I have a NSString with #"12.34" and I want to convert it into a NSString with the same float number but in single precision 32bits binary floating-point format IEEE-754 : like #"\x41\x45\x70\xa4" (with hexa characters) or #"AEpĀ¤"...
I'm sure it's something easy but after many hours of reading the doc without finding a solution...
Thank you !
As Yuji mentioned, it's not a good idea to encode an arbitrary byte sequence into an NSString(although it can contain null bytes), as encoding transformations can(and probably WILL) destroy your byte sequence. If you want access to the raw bytes of a float, you may want to consider storing them as an NSData object(though I suggest you think through your reasons for wanting this first). To do this:
NSString *string = #"10.23";
float myFloat = [string floatValue];
NSData *myData = [[NSData alloc] initWithBytes:&myFloat length:sizeof(myFloat)];
If you want to get the raw bytes of a float, you could cast it, like so:
NSString *str = #"12.34";
float flt = [str floatValue];
unsigned char *bytes = (unsigned char *)&flt;
printf("Bytes: %x %x %x %x\n", bytes[0], bytes[1], bytes[2], bytes[3]);
However the order in which these bytes are stored in the array depends on the machine. (See http://en.wikipedia.org/wiki/Endianness). For example, on my Intel iMac it prints: "Bytes: a4 70 45 41".
To make a new NSString from an array of bytes you can use initWithBytes:length:encoding:
I need to convert a long value from int64 to NSData, so I can later run a hash algorithm on it. I perform:
int64_t longNumber = 9000000000000000000L;
NSMutableData *buffer = [NSMutableData dataWithBytes:&longNumber length:sizeof(longNumber)];
NSLog(#"%lld", [buffer bytes]);
NSLog(#"%lld", longNumber);
The resultant console output is like this:
6201314301187184
9000000000000000000
Why is NSData not properly storing the value of the long number? If I run this in a loop, the NSData bytes drift, starting with 620, then 621 and on. Am I outputting the address of the longNumber via [buffer bytes] and not its value?
You have two major issues: first, your number is too large for the long that you are casting it to. Instead of 9000000000000000000L you should have 9000000000000000000LL to indicate a long long constant.
Second, you answered your question correctly, you are printing out an address. Replace your NSLog line with with this line:
NSLog(#"%lld", *((int64_t*)[buffer bytes]));
and you should see the result you expect.