I am trying to send an Array from one player to another.
I create a struct in the header
typedef struct {
Message message;
unsigned int numBytes;
void * bytes;
} MessagePingBackToCaller;
typedef struct {
MessageType messageType;
} Message;
And try to send with this:
-(void)sendOpponentRadar{
MessagePingBackToCaller sendMessage;
sendMessage.message.messageType = kMessageTypeRecievedRadarPing;
NSData *pingData = [NSKeyedArchiver archivedDataWithRootObject:[cover gatherAndReturnColumnNumbers]];
sendMessage.bytes = pingData;
NSData *data = [NSData dataWithBytes:&sendMessage length:sizeof(MessagePingBackToCaller)];
[self sendData:data];
}
And receive with this:
if (message->messageType == kMessageTypeRecievedRadarPing){
MessagePingBackToCaller *messageSent = (MessagePingBackToCaller *)[data bytes];
NSLog(@"Data : %@", messageSent->bytes);
NSMutableArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:messageSent->bytes];
NSLog(@"Results : %@", array);
}
However no luck, so I went looking around and found that @rwenderlich wrote a little helpful bit:
Convert NSArray to NSData
In struct, store an unsigned int numBytes, and a void * bytes
In numBytes, write the length of the NSData, and then write out the contents of the NSData
On the other side, read numBytes to see how many bytes to read next, then read in that amount of bytes and reverse the process (bytes->NSData->NSArray).
Im pretty good on 1 and 2... I believe, but i get lost on 3 and 4. Could someone please help me translate this into meaningful code?
Thanks!
You can just use NSKeyedArchiver to do the trick, dont use the c struct, make it an objective-c class, get data from the thing using NSKeyedArchiver and send that, then just unarchive in the other side, heres an example for an arbitrary class
interface
@interface GameState : NSObject
{
//enum for session state
SessionState _currentState;
NSData *_data;
NSString *_message;
NSDate *_timestamp;
}
@property(nonatomic,retain) NSDate *timestamp;
@property(assign) SessionState currentState;
@property(nonatomic,retain) NSData *data;
@property(nonatomic,retain) NSString *message;
- (id)initWithCoder:(NSCoder *)coder;
implementation
@implementation GameState
@synthesize message=_message , currentState= _currentState, data=_data;
@synthesize timestamp=_timestamp;
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
_killPlayback=FALSE;
_lastPacket=FALSE;
_number=0.0;
_pass=FALSE;
_timestamp=NULL;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:_timestamp forKey:@"Timestamp"];
[coder encodeObject:_message forKey:@"Message"];
[coder encodeObject:_data forKey:@"Data"];
[coder encodeInt:_currentState forKey:@"State"];
}
// Decode an object from an archive
- (id)initWithCoder:(NSCoder *)coder
{
self = [super init];
_message = [[coder decodeObjectForKey:@"Message"] retain];
_data = [[coder decodeObjectForKey:@"Data"] retain];
_currentState=(SessionState)[coder decodeIntForKey:@"State"];
_timestamp=[[coder decodeObjectForKey:@"Timestamp"] retain];
return self;
}
@end
now you can get data from the object like
-(NSData*)dataFromObject:(id)obj
{
return [NSKeyedArchiver archivedDataWithRootObject:obj];
}
and an object from the data
-(id)objectFromData:(NSData*)data
{
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
and your workflow becomes
on the sender side
GameState *state=..;
NSData* data=[self dataFromObject:state];
//send the data
and on the receiving side
GameState *state=[self objectFromData:data];
hope it helps
You might also try the following to get compressed data (about 1/5 the size of the original):
-(NSData*)compressedMatchDataFromMatchState:(NSMutableDictionary*)matchState
{
NSError* error = nil;
NSData* compressedMatchData = [NSPropertyListSerialization dataWithPropertyList:matchState format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error];
return compressedMatchData;
}
-(NSMutableDictionary*)matchStateFromCompressedMatchData:(NSData*)compressedMatchData
{
NSError* error = nil;
NSPropertyListFormat plf = NSPropertyListMutableContainersAndLeaves;
NSMutableDictionary* matchState = [NSPropertyListSerialization propertyListWithData:compressedMatchData options:NSPropertyListMutableContainersAndLeaves format:&plf error:&error];
return matchState;
}