I have some NSData instance with 2 bytes of different value.
Will calling getBytes: of any kind (length, range...) also advance the current position in the buffer?
Example:
NSData *data = ...; // 2 bytes data
[data getBytes:&whatever1 length:1]; // reading first byte
[data getBytes:&whatever2 length:1]; // reading first OR second byte?
Will the contents that I get on each time getBytes:length: is called be the same first byte in the NSData instance or will the first call advance the next call to read from the second byte?
Thanks!
No, it does not.
In the example it will access the same byte (first).
To access the "next" byte you'll need to use getBytes:range: but, like #hot-licks commented, NSData is immutable and therefore won't be modified.
Related
I'm new in the area of Objective-C.
My question is, how can I Send a byte format like b70f using NSData?
So, basically I have to make a variable first with the value of b70f and then write it to the peripheral.
[peripheral writeValue:[NSData dataWithBytes:&value length:1] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
How can I do this?
Any help would be appreciated.
Assuming that b70f is a 16-bit value, something like this should work...
uint16_t value = 0xb70f;
NSData *data = [NSData dataWithBytes:&value length:2];
This takes advantage that an "array" of two bytes fits into a single 16-bit integer.
If the bytes are in the wrong order, wrap the assignment with OSSwapInt16().
uint16_t value = OSSwapInt16(0xb70f);
I haven't found any get equivalent to appendBytes. If I've understood getBytes correctly, that method always returns bytes from the start of the buffer. It will not increment.
What's the reason for this?
I'm not sure what you mean, equivalent? appendBytes adds while getBytes gets, they're complete opposites. This is a nice method I use to get bytes when there's different data in the buffer. It shows a nice use of getBytes:range:
UInt16 anUInt16;
float aFloat;
int position = 0;
[data getBytes:&anUInt16 range:NSMakeRange(position, sizeof(UInt16))];
position += sizeof(UInt16);
[data getBytes:&aFloat range:NSMakeRange(position, sizeof(float))];
position += sizeof(float);
and so on...
There are several methods that give you access to some part of the data in a NSData object. For example, you can use -getBytes:range: to copy the data specified by a NSRange into a buffer. Or you can use -subdataWithRange: to get a NSData that contains just a portion of another.
If you want to read sequentially through the contents of a NSData object, you can create a NSInputStream and initialize it with your NSData, and then read from the stream using -getBuffer:length: or -read:maxLength:.
NSInputStream *stream = [[NSInputStream alloc] initWithData:myData];
[stream open];
while ([stream read:&buffer maxLength:bufferLength] > 0) {
// do something with buffer
}
Note: you obviously don't need the while loop in the code above if you're not doing the same thing to each chunk of data that you read -- I just included it because it's a common way to read data.
Your question is not clear.
If you need to get bytes from a specific offset, simply use the getBytes:range: method.
- ( void )getBytes: ( void * )buffer range: ( NSRange )range;
For instance:
char buf[ 4 ];
// Get 4 bytes from offset 2
[ dataObject getBytes: buf range: NSMakeRange( 2, 4 ) ];
If you're looking for appendBytes, then use NSMutableData, which inherits from NSData and adds mutability options, just as NSArray and NSMutableArray.
- ( void )appendBytes: ( const void * )bytes length: ( NSUInteger )length;
You can get a NSMutableData from a NSData using the mutableCopy method. Note that you own the resulting object.
NSMutableData * mData;
mData = [ dataObject mutableCopy ];
[ mData appendBytes: ( const void * )"abcd" length: 4 ];
[ mData release ]
You may be looking for -[NSData getBytes:range:], which lets you specify the range of data that you want to read from the buffer. Another option is -[NSData subdataWithRange:], which actually returns another NSData instance that contains only the bytes in the specified range.
I have an original NSData type which contains let's say 100 bytes. I want to get 2 other NSData types. The first containing the first 20 bytes of the 100, and the second one containing the other 80.
They should be copied from the original NSData. Sorry if I wasn't so clear, but I'm pretty new with Objective-C.
You can use NSData's -(NSData *)subdataWithRange:(NSRange)range; to do that.
From your example, here is some code :
// original data in myData
NSData *d1 = [myData subdataWithRange:NSMakeRange(0, 20)];
NSData *d2 = [myData subdataWithRange:NSMakeRange(20, 80)];
Of course, the ranges are immediate here, you will probably have to do calculations, to make it work for your actual code.
Swift 3
let subdata1 = data?.subdata(in: 0..<20)
let subdata2 = data?.subdata(in: 20..<80)
Due to this is question is in very top of Google Search I wanna write here an example for swift
NSData *mainData = /*This is you actual Data*/
NSData *fPart = [mainData subdataWithRange:NSMakeRange(0, 20)];
NSData *sPart = [mainData subdataWithRange:NSMakeRange(20, 80)];
Instead 80 you can use some dynamic - like data length
I'm trying to send hexadecimal data via WiFi.
The code is something like this:
NSString *abc = #"0x1b 0x50";
NSData *data = [[[NSData alloc] initWithData:[abc dataUsingEncoding:NSASCIIStringEncoding]]autorelease];
[outputStream write:[data bytes] maxLength:[data length]]];
Instead of sending the hexadecimal data, it's sending it in text format.
I tried with NSUTF8StringEncoding, but it's the same. I'm using it with the NSStream class.
You're not getting what you expect with NSString *abc = #"0x1b 0x50". It's almost the same as having NSString *abc = #"cat dog 123 0x0x0x"; just a bunch of words separated by spaces. So when you create your NSData object, you're just initializing it with a string of characters, not a series of actual numbers.
If you can get your numbers into an NSArray, this question/answer should help you: How to convert NSArray to NSData?
The data that you probably want to send is simply 0x1b50, which is the decimal number 6992 (assuming big-endian), and fits into two bytes. This is not the same as a string (which could contain anything) even if it happens to contain some human-readable representation of those numbers.
I'm assuming you want to send this as binary data, and if so one way would be to simply send a buffer formed by a single UInt16 instead of a string. I'm not very familiar with the relevant APIs, but look to see if you can populate the NSData with an integer, perhaps something like:
UInt16 i = 0x1b50; // Or = 6992
[[NSData alloc] initWithBytes: &i length: sizeof(i)]
[outputStream write: [data bytes] maxLength: [data length]]];
Again, I'm not fluent with Objective C, but this should be the general approach to sending the number 0x1b50 as binary data.
Why does the following code produce the logging at the bottom ?
Here is the anomaly- my second NSLog should print the chrStr but produces nothing, empty, which is verified by this debug command:
(gdb) po chrStr
object returns empty description
However, the third NSString where I re-convert the NSString back to NSData object DOES display the the data, the same value as in the first NSLog, as it should. This would indicate to me that chrStr must have actual contents. But it seems not to be so from the NSLOG or the po command. Why ?
NSString *login;
NSString *pass;
// Purpose: NSString *loginString = [NSString stringWithFormat:#"\000%#\000%#", login, pass];
login = #"Loginname"; // text string1
pass = #"Password"; // text string2
// convert text strings to data objects
NSData *subData1 = [login dataUsingEncoding:NSUTF8StringEncoding];
NSData *subData2 = [pass dataUsingEncoding:NSUTF8StringEncoding];
// embed a NULL into new NSData object
NSMutableData *data = [NSMutableData data];
unsigned char zeroByte = 0;
[data appendBytes:&zeroByte length:1];
// append string1, NULL, string2 to data object
[data appendData:subData1];
[data appendBytes:&zeroByte length:1];
[data appendData:subData2];
NSLog(#"1.NSData: %#", data); // print data object
// create a character string from data object
NSString *chrStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"2.NSString: %#", chrStr); // print character string
// create data object from string object
NSData *chrData = [chrStr dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"3.NSDATA: %#", chrData); // print data object
Produces:
[1071:207] 1.NSData: 004c6f67 696e6e61 6d650050 61737377 6f7264
[1071:207] 2.NSString:
[1071:207] 3.NSDATA: 004c6f67 696e6e61 6d650050 61737377 6f7264
This is a real mystery to me. If chrStr is empty then 3-NSDATA could not display its info, but it does !
What am I trying to accomplish ? Well, check my very first comment line: // purpose:
That line when uncommented produces a warning, even though it actually works, so I was trying to do it another way that allowed me to have a clean compile. If you see a better way to accomplish that objective, I all eyes and ears. But please don't dwell on why that #"\000%#\000%#" string is necessary, start out accepting that it is. Thanks.
In C (and therefore objective-c), a null byte is used to represent the end of a string. When you create the string object, it takes all of the data you have given it without parsing, which is why you can convert it back to data successfully. However, when you display the string, the system reads the string up to the first null byte, which is the first byte. Therefore, the string contains data, but any system functions which read byte by byte instead of using the strings returned length will think it is empty. When you work with non-displayable characters, you should try to use data objects over string objects as often as possible.