Pregunta

Estoy trabajando con Objective-C y tengo que añadir de int de un NSArray a un NSMutableData (estoy preparando una para enviar los datos a través de una conexión). Si envuelvo la década de int con NSNumber y luego añadirlos a NSMutableData, ¿cómo iba a saber cuántos bytes están en el int NSNumber? ¿Sería posible utilizar sizeof () ya que de acuerdo a la documentación de manzana, "NSNumber es una subclase de NSValue que ofrece un valor como cualquier escalar C (numérico) de tipo."?

Ejemplo:

NSNumber *numero = [[NSNumber alloc] initWithInt:5];

NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0];

[data appendBytes:numero length:sizeof(numero)];
¿Fue útil?

Solución

numero no es un valor numérico, es un puntero a un objeto represting un valor numérico. Lo que estamos tratando de hacer no va a funcionar, el tamaño será siempre igual a un puntero (4 para las plataformas de 32 bits y 8 para 64 bits), y se añadirá un valor de puntero de basura a sus datos en comparación con el número.

Incluso si usted fuera a tratar de eliminar la referencia, no se puede acceder directamente a los bytes que respaldan un NSNumber y esperar que funcione. Lo que está pasando es un detalle de implementación interna, y puede variar de una versión a otra, o incluso entre diferentes configuraciones del mismo de liberación (32 bits vs 64 bits, iPhone vs Mac OS X, el brazo vs i386 vs PPC). Sólo empacar los bytes y enviarlos a través del cable puede resultar en algo que no deserializar correctamente en el otro lado, incluso si se las arregló para llegar a los datos reales.

Lo que realmente necesitan para llegar a una codificación de un número entero que puede poner en sus datos y luego empaquetar y desempaquetar los NSNumbers en eso. Algo así como:

NSNumber *myNumber = ... //(get a value somehow)
int32_t myInteger = [myNumber integerValue]; //Get the integerValue out of the number
int32_t networkInteger = htonl(myInteger); //Convert the integer to network endian
[data appendBytes:&networkInteger sizeof(networkInteger)]; //stuff it into the data

En el lado receptor, a continuación, agarrar el número entero y que reconstruya un NSNumber con numberWithInteger:. Ntohl después de usar para convertir a formato huésped nativo

Se puede requerir un poco más de trabajo si usted está tratando de enviar representaciones mínimas, etc.

La otra opción es utilizar una subclase NSCoder y decirle al NSNumber para codificar a sí mismo usando su codificador, ya que será una plataforma neutral, pero puede ser excesiva para lo que está tratando de hacer.

Otros consejos

En primer lugar, NSNumber * numero es "Un puntero a un tipo NSNumber", y el tipo NSNumber es un objeto de Objective-C. En general, a menos que se especifique en algún lugar de la documentación, la regla de oro en la programación orientada a objetos es que "Los detalles internos de cómo un objeto elige para representar a su estado interno es privado para la implementación de objetos, y deben ser tratados como un negro caja." Una vez más, a menos que la documentación dice que se puede hacer de otra manera, no se puede asumir que NSNumber está utilizando un tipo primitivo de C int para almacenar el valor int que le dio.

La siguiente es una aproximación de lo que está pasando 'entre bastidores' cuando appendBytes:numero:

typedef struct {
  Class isa;
  double dbl;
  long long ll;
} NSNumber;

NSNumber *numero = malloc(sizeof(NSNumber));
memset(numero, 0, sizeof(NSNumber));
numero->isa = objc_getClass("NSNumber");

void *bytes = malloc(1024);

memcpy(bytes, numero, sizeof(numero)); // sizeof(numero) == sizeof(void *)

Esto hace que sea un poco más claro que lo que estás añadiendo a la NSMutableData objeto es data los primeros cuatro bytes de lo que cada vez numero está apuntando a (que, para un objeto en Obj-C siempre es isa, la clase de objetos ). Sospecho que lo que "quería" hacer era copiar el puntero al objeto instanciado (el valor de numero), en cuyo caso se debe tener &numero utilizado. Este es un problema si usted está usando GC como el tampón utilizado por NSMutableData no es escaneado (es decir, el sistema de GC ya no "ver" el objeto y recuperar, lo que es prácticamente una garantía de un accidente al azar en algún tarde punto).

Es de esperar que obvio que incluso si se pone el puntero al objeto instanciado en NSNumber a data, ese puntero sólo tiene sentido en el contexto del proceso que lo creó. Un puntero a ese objeto es aún menos significativa si se envía ese puntero a otro por ordenador el equipo receptor no tiene forma (práctico, trivial) para leer la memoria que el puntero apunta en el ordenador emisor.

Ya que parece estar teniendo problemas con esta parte del proceso, vamos a hacer una recomendación que le ahorrará muchas horas de depuración de algunos errores de implementación extremadamente difíciles que está obligado a ejecutar a:

Abandonar toda esta idea de intentar enviar datos binarios sin formato entre las máquinas y acaba de enviar información con formato ASCII simple / UTF-8 entre ellos.

Si usted piensa que esto es de alguna forma va a ser lenta o ineficiente, entonces déjame recomiendo que llevar cada cosa utilizando un sistema simplificado ASCII / UTF-8 versión Stringified primero. Confía en mí, la depuración de datos binarios en bruto no es divertido, y la capacidad de simplemente NSLog(@"I got: %@", dataString) vale su peso en oro cuando se está depuración de los problemas inevitables. Entonces, una vez que todo ha gelificado, y que está seguro de que no es necesario realizar más cambios a qué es lo que necesita intercambiar, "puerto" (a falta de una palabra mejor) que la aplicación de una única versión binaria si, y sólo si , de perfiles con Shark.app lo identifica como un área del problema. Como punto de referencia, en estos días puedo scp un archivo entre máquinas y saturar un enlace Gigabit con la transferencia. scp tiene que ver probablemente alrededor de cinco mil veces más procesamiento por byte para comprimir y cifrar los datos que este sencillo stringification todo durante la transferencia de 80 MB / seg. Sin embargo, en el hardware moderno esto es apenas suficiente para mover el medidor en funcionamiento de la CPU en mi barra de menú.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top