Desarrollo de iOS: ¿Cómo puedo encapsular una cadena en un objeto NSData?

Estoy creando un juego multijugador en el iPhone y necesito enviar datos de cadena a los otros jugadores del juego. Para hacer eso, necesito encapsular mis datos de cadena NSString * en un objeto NSData de alguna manera. Aquí hay un ejemplo de cómo está estructurado mi código ...

typedef struct 
{
   PACKETTYPE packetType;
   ??? stringToSend;  //<---not sure how to store this
} StringPacket;    

StringPacket msg;
msg.packetType = STRING_PACKET;
msg.stringToSend = ...  //  <---not sure what to do here
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(StringPacket)];

Entonces mi pregunta es, si StringPacket es una estructura definida en mi encabezado, ¿qué tipo debería stringToSend propiedad sea de modo que pueda llamar fácilmente al dataWithBytes método de NSData encapsular los datos del paquete en un objeto NSData?

¡Gracias por tu sabiduría!

preguntado el 08 de enero de 11 a las 17:01

2 Respuestas

Al principio, debe convertir su NSString a la representación UTF8 a través de [NSString UTF8String]. Después de eso, recomendaría almacenar en la longitud de la cadena del paquete, y después de eso, los caracteres de la cadena ellos mismos. Todo eso se puede hacer agregando NSData, creado a partir de char * a través de [NSData dataWithBytes:]

NSMutableData packet = [[NSMutableData alloc] init];
[packet appendBytes:&msg.packetType, sizeof(msg.packetType)];
char *str = [yourString UTF8String];
int len = strlen(str);
[packet appendBytes:(void*)&len, sizeof(len)];
[packet appendBytes:(void*)str, len];

Para analizar el paquete de nuevo, debe hacer:

NSData packet; // your packet
[packet getBytes:(void*)&packet.msg range:NSMakeRange(0, sizeof(packet.msg))];
int len;
[packet getBytes:(void*)&len range:NSMakeRange(sizeof(packet.msg), sizeof(len)];
NSData *strData = [packet subdataWithRange:NSMakeRange(sizeof(packet.msg) + sizeof(len)), packet.length];
NSString *str = [[NSString alloc] initWithData:strData encoding:UTF8Encoding];

Puede haber algunos errores ya que estoy escribiendo de memoria, pero creo que entenderás la idea.

Respondido el 08 de enero de 11 a las 20:01

gracias, nickolay! No tengo claro lo que quiere decir con "almacenar en la longitud de la cadena del paquete", ¿quiere decir crear una propiedad adicional que almacene la longitud de la cadena? Además, no tengo claro a qué te refieres con agregar NSData. si no es demasiado trabajo, ¿le importaría mostrar un ejemplo rápido? ¡gracias de nuevo! - BeachRunnerFred

Agregué ediciones a mi publicación para preservar el formato para una mejor legibilidad. - Nickolay Olshevsky

Gracias, Nickolay, parece muy sencillo. Una pregunta más, cuando los datos llegan al otro extremo y accedo a los datos usando el método de 'bytes' de la clase NSData, ¿cómo puedo acceder a estos fragmentos individuales de bytes si la longitud de la cadena es dinámica? - BeachRunnerFred

Si sus cuerdas tienen una longitud máxima, es bastante fácil y se puede hacer de manera eficiente. Entonces, asumiendo que la longitud máxima de sus cadenas para estos paquetes es 255 y ha decidido usar UTF-8 para codificar sus cadenas (ambos lados deben acordar qué codificación están usando), podría hacerlo así:

typedef struct 
{
   PACKETTYPE packetType;
   uint8_t stringToSend[256];  // UTF8 string with max encoded length of 255 bytes
} StringPacket;    

StringPacket msg;
msg.packetType = STRING_PACKET;
[theString getCString:msg.stringToSend maxLength:256 encoding:NSUTF8StringEncoding];
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(StringPacket)];

Ahora tendrá una cadena C adecuada en su paquete que tiene como máximo 255 bytes de datos de cadena y el terminador nulo. Tenga en cuenta que si su cadena no se puede codificar en UTF8 en el tamaño que le dio, el método devolverá NO, por lo que su código real debería verificarlo y manejarlo.

Si no puede tener un límite de tamaño, básicamente puede hacer lo mismo, pero tiene que lidiar con la asignación dinámica de la memoria, la copia de los bytes, la creación de los datos y la liberación adecuada de la memoria en el momento adecuado, por lo que se vuelve mucho más involucrado pero es la misma idea básica. Ver también el método -getBytes:maxLength:usedLength:encoding:options:range:remainingRange: en NSString, puede ser muy útil para generar estos mensajes donde el tamaño de la cadena es dinámico y totalmente desconocido.

Para el caso más simple, sin embargo, el código anterior debería hacer el trabajo.

Respondido el 08 de enero de 11 a las 20:01

Esto no tiene en cuenta la longitud de cadena diferente, por lo que para cadenas más cortas enviará una sobrecarga y para cadenas más largas las truncará. - Nickolay Olshevsky

@Nickolay: Sí, definitivamente enviará sus 256 bytes cada vez, pero como ya dije, no truncará la cadena, fallará la llamada por completo y tendrías que verificar eso. - Jason Coco

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.