Отправка и получение NSMutableArray в виде байтов с использованием GameKit

Я пытаюсь отправить массив от одного игрока к другому.

Я создаю структуру в заголовке

typedef struct {
    Message message;
    unsigned int numBytes;
    void * bytes;
} MessagePingBackToCaller;

typedef struct {
    MessageType messageType;
} Message;

И попробуйте отправить с этим:

-(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];
}

И получить с этим:

if (message->messageType == kMessageTypeRecievedRadarPing){

        MessagePingBackToCaller *messageSent = (MessagePingBackToCaller *)[data bytes];

        NSLog(@"Data : %@", messageSent->bytes);

        NSMutableArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:messageSent->bytes];
        NSLog(@"Results : %@", array);
    }

Однако не повезло, поэтому я огляделся и обнаружил, что @rwenderlich написал немного полезного:

  1. Преобразование NSArray в NSData

  2. В структуре сохраните unsigned int numBytes и void * bytes

  3. В numBytes запишите длину NSData, а затем запишите содержимое NSData

  4. С другой стороны, прочитайте numBytes, чтобы увидеть, сколько байтов нужно прочитать дальше, затем прочитайте это количество байтов и выполните обратный процесс (bytes-> NSData-> NSArray).

Я неплохо разбираюсь в 1 и 2... Верю, но теряюсь в 3 и 4. Не мог бы кто-нибудь помочь мне перевести это в осмысленный код?

Спасибо!


person James Dunay    schedule 30.01.2012    source источник
comment
я не думаю, что это утверждение, NSData *data = [NSData dataWithBytes:&sendMessage length:sizeof(MessagePingBackToCaller)]; возвращает то, что вы ожидаете, sizeof(MessagePinkBackToCaller) не будет размером фактического объекта sendMessage, он вернет размер пространства класса MessagePinkBackToCaller, которое содержит указатели, а не фактические объекты, для одного он вернет void * как указатель 4 байта, хотя на самом деле это может быть любой размер, что-то не отраженное в sizeof( поэтому в этом случае вы не можете использовать sizeof..   -  person Daniel    schedule 31.01.2012
comment
кое-что из этого, возможно, пришло мне в голову, но что вы могли бы предложить?   -  person James Dunay    schedule 31.01.2012
comment
Есть ли причина, по которой ваше сообщение отправки является структурой c?   -  person Daniel    schedule 31.01.2012
comment
Ну, я просто не знаю другого пути :/   -  person James Dunay    schedule 31.01.2012
comment
только что отправил ответ, проверьте, я ту   -  person Daniel    schedule 31.01.2012


Ответы (2)


Вы можете просто использовать NSKeyedArchiver, чтобы добиться цели, не используйте структуру c, сделайте ее классом Objective-C, получите данные с помощью NSKeyedArchiver и отправьте их, а затем просто разархивируйте с другой стороны, вот пример для произвольного класса

интерфейс

@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 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

теперь вы можете получить данные от объекта, например

-(NSData*)dataFromObject:(id)obj
{
    return [NSKeyedArchiver archivedDataWithRootObject:obj];
}

и объект из данных

-(id)objectFromData:(NSData*)data
{
    return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}

и ваш рабочий процесс становится на стороне отправителя

GameState *state=..;
NSData* data=[self dataFromObject:state];
//send the data

и на принимающей стороне

GameState *state=[self objectFromData:data];

Надеюсь, поможет

person Daniel    schedule 31.01.2012
comment
Хорошо, так что просто пытаюсь прояснить все это в моей голове. Итак, я сохраняю все данные, которые мне нужны, в GameState, т.е. NSStrings и Arrays и такие как _message и _data? Как только это будет сделано, я сжимаю все это как NSData, используя dataFromObject: а затем использую свой метод отправки для отправки данных по проводу и распаковки на другом конце? - person James Dunay; 01.02.2012
comment
Также не могли бы вы написать мне краткий пример того, как использовать initWithCoder: (как передать _message и _data?) - person James Dunay; 01.02.2012
comment
АААА!!! Неважно, у меня это работает! Однако мне нужно подробнее взглянуть на NSCoder, потому что я думаю, что разделал ваш код. Но большое спасибо за ваше объяснение. - person James Dunay; 01.02.2012
comment
Примечание для других людей, это будет работать, только если ваш класс имеет протокол NSCoder, т.е. поэтому NSManagedObject не будет работать, потому что он не реализует этот протокол. - person Luke; 13.03.2013

Вы также можете попробовать следующее, чтобы получить сжатые данные (примерно 1/5 размера оригинала):

-(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;
 }
person billh    schedule 04.03.2012