Obj-C/iOS: How to retrieve contents of NSData and interact? - iphone

I'm retrieving a unix timestamp from a Bluetooth LE peripheral, which is stored in an NSData object. If I print the contents of the NSData object to the debug console, they appear correct, however if I try to convert the NSData object to an integer value, the integer value appears to keep changing.
NSData *refinedData = [mfrData subdataWithRange:range];
Which yields a value of 386d5e9a on the debug console.
I then convert to an integer:
uint32_t unixTimeStamp = refinedData;
Initially, this yields a value of 342162144 on the debug console. However, this value keeps growing, despite the NSData not changing. Can anybody help me understand what's going on?
If it's not already very apparent, I'm a newbie.
Thanks.

refinedData is a pointer to an instance of NSData. You want to access its contents:
uint32_t unixTimeStamp = *(uint32_t *)[refinedData bytes];
Note that this is simplified, and assumes that the bytes returned by the Bluetooth peripheral are the same endianness as the processor in your device, that range is correct, etc.

Related

data loss when sending across type NSData

I am currently in the middle of implementing the network layer of my game, i am making progress however i have come across something very odd which i was hoping someone could shed some might on:
Before sending my data across i am encoding it into type NSData (message.cards = [MovePlayer beginEncodeMyCards:myCards];) and then assigning it to a pointer (message.cards)
MessageMove message;
message.message.messageType = kMessageTypeMove;
/**/message.cards = [MovePlayer beginEncodeMyCards:myCards];/**/
NSData *data = [NSData dataWithBytes:&message length:sizeof(message)];
If i do all the decoding on the client side as follows :
MessageMove *myMessage = (MessageMove *) [data bytes];
/**/myCards = [MovePlayer beginDecodeMyCards:myMessage->cards cardArray:myCards];/**/
everything works fine, i am able to decode myMessage->cards, however when i try doing the same after sending the object remotely i can see the correct message type (kMessageTypeMove) but not the cards data (myMessage->cards).
if anyone can please shed some light to this i would greatly appreciate it
many thanks
tl;dr, use NSCoding to serialise your objects.
You can't send pointers to a different process, because the pointers will all be wrong on the other side.
Lets say on the sending machine, you have this:
NSLog(#"cards: %p", message.cards);
//prints "cards: 0xDEADBEEF"
This says that the chunk of memory for the NSArray* object starts at the memory address 0xDEADBEEF. This is all correct at this point.
Now, you send that 0xDEADBEEF pointer to another computer. The computer gets the pointer, but the memory at 0xDEADBEEF does not have an NSArray in it on the other computer. There could be anything in that region of memory. You've sent a pointer, but you haven't actually sent any of the data with it.
Long story short, just use NSCoder for serialisation because it's very good.

Getting length of NSMutableData

I have managed to NSInputStream and read some data to NSMutableData object. I am able to put this data into string and NSLog it, however when I try to access its length(I am assuming this is its size in bytes) my app crashes.
NSString *stringData=[[NSString alloc]initWithData:self.data encoding:NSUTF8StringEncoding];
NSLog(#"%# thats data",stringData);//logs out content of data
NSLog(#"%# thats data length",[self.data length]);//crashes
So my question is if I call copy on NSMutableDate do I get immutable copy ?
Am I tying to access the length in a wrong manner ?
It's because you are trying to log the length as an object using %#. It's not an object, it's an integer, so log it with %i instead:
NSLog(#"%i thats data length",[self.data length]);
Logging an object with %# tries to call the [... description] method on whatever is passed in. You can imagine the horrors that occur in the application memory when it tries to call that method on a random integer, thinking that it's a pointer to an object.

How do I extract a single byte from within a string on iPhone?

In Android, I can extract a single byte from within a string using code like the following:
byte[] arrByte = String.getBytes(); .
If I wanted to do this on the iPhone in Objective-C, how could I accomplish the same task? Additionally, how could I get a byte for a given index in the string?
If you take a look at the NSString reference you will get various methods to get the data from a string. An example is
NSData *bytes = [yourString dataUsingEncoding:NSUTF8StringEncoding];
You can also make use of the method UTF8String

NSData over GameKit and EXC_BAD_ACCESS strange problem

I'm trying to stream video data over a peer-to-peer connection created with GameKit. I have a method that receives an NSData object and uses it to draw a video stream onto a CALayer:
- (void)recieveVideoFromData:(NSData *)data;
Here are the first few lines of that method which convert the NSData to CMSampleBufferRefs and begins processing:
CMSampleBufferRef imgData = (CMSampleBufferRef)data.bytes;
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(imgData);
CVPixelBufferLockBaseAddress(imageBuffer,0);
Now, when I feed the video stream from the local camera into this method as follows, everything works just fine and the video stream displays on screen:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
NSData *data = [[NSData alloc] initWithBytes:sampleBuffer length:malloc_size(sampleBuffer)];
[self recieveVideoFromData:data];
}
But, when I send a stream of those NSData packets over a peer-to-peer connection and receive them in the following fashion, I get an EXC_BAD_ACCESS error:
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
[self recieveVideoFromData:data];
}
Using the debugger, I learned that the bad access occurs on this line:
CVPixelBufferLockBaseAddress(imageBuffer,0);
I have no idea why the NSData sent over the network should be any different than the NSData sent from another method on the same device. I have checked that the data received over the network is being received at the same interval and is the same length (336 bytes) as the data produced on the local device. I also checked the retain count of the data object is 1 before it is used. It seems that the imageBuffer variable is somehow getting lost.
A couple of questions:
Is casting data.bytes to a CMSampleBufferRef the right way to go about unpacking NSData?
How do I assert that the data being received is actually a CMSampleBuffer object? I want to protect my code but I'm not sure how to accomplish a class verification for Core Foundation classes.
Thanks in advance!
Why are you 'unpacking' (that's not unpacking) your CMSampleBuffer by casting the bytes of NSData? That's never going to work, because CMSampleBuffer is not a continuous block in memory.
You have to retrieve all the relevant data from a CMSampleBuffer yourself before sending, stuff it into and NSData object, and reasemble it on the other side via
OSStatus CMSampleBufferCreate (
CFAllocatorRef allocator,
CMBlockBufferRef dataBuffer,
Boolean dataReady,
CMSampleBufferMakeDataReadyCallback makeDataReadyCallback,
void *makeDataReadyRefcon,
CMFormatDescriptionRef formatDescription,
CMItemCount numSamples,
CMItemCount numSampleTimingEntries,
const CMSampleTimingInfo *sampleTimingArray,
CMItemCount numSampleSizeEntries,
const size_t *sampleSizeArray,
CMSampleBufferRef *sBufOut
);
The data types in this function might give you a hint what you want to extract from the CMSampleBuffer when packing your data.
This is probably not the entire answer, but your use of malloc_size seems like a huge red flag to me. This seems a non-portable extension, not governed by anything like ANSI, ISO or POSIX, and I have some doubts on how it might behave if passed a buffer that didn't come from malloc. It seems like a sketchy thing to rely on. (I would say if it's come to calling malloc_size you're already doing something wrong as a C coder, since C is all about knowing how big your buffers are upfront and not relying on non-portable libc functions to do your buffer-size-tracking work for you.)

NSData to NSString using initWithBytes:length:encoding

I have some image data (jpeg) I want to send from my iPhone app to my webservice. In order to do this, I'm using the NSData from the image and converting it into a string which will be placed in my JSON.
Currently, I'm doing this:
NSString *secondString = [[NSString alloc] initWithBytes:[result bytes]
length:[result length]
encoding:NSUTF8StringEncoding];
Where result is of type NSData. However, secondString appears to be null even though result length returns a real value (like 14189). I used this method since result is raw data and not null-terminated.
Am I doing something wrong? I've used this code in other areas and it seems to work fine (but those areas I'm currently using it involve text not image data).
TIA.
For binary data, better to encode it using Base64 encoding then decode it in you webservice. I use NSData+Base64 class downloaded from here, this reference was also taken from Stackoverflow, an answer made by #Ken (Thanks Ken!).
You are not converting the data to a string. You are attempting to interpret it as a UTF-8 encoded string, which will fail unless the data really is a UTF-8 encoded string. Your best bet is to encode it somehow, perhaps with Base64 as Manny suggests, and then decode it again on the server.