objective-c nsnumber

objective c - ¿Por qué es NSNumber inmutable?



objective-c (6)

¿Por qué es NSNumber inmutable? ¿Hubo una buena razón? Porque ahora estoy pensando en crear mi propia clase solo por la mutabilidad.


Creo que todos tuvieron una buena respuesta, excepto quizás 9000. No estoy seguro de a qué se refiere, aunque tal vez esté por encima de mi cabeza.

La decisión de hacer que NSNumber sea inmutable es una decisión de diseño de los creadores de Foundation Framework. Creo que todos podemos estar de acuerdo en eso.

Supongo que la razón por la que hicieron eso fue porque se hace referencia a todos los objetos instanciados en Objective-C mediante punteros, incluido NSNumber. Esto causa algunos problemas de diseño al pasar NSNumber alrededor. Digamos que creas una clase llamada "Persona", con una propiedad NSNumber, "myAge". Por lo tanto, su aplicación crea una instancia de Person y establece myAge en 28. Alguna otra parte de la aplicación ahora pregunta al objeto Person para su antigüedad, y devuelve (NSNumber *) myAge, o un puntero al objeto NSNumber que envuelve el valor 28 . Desde que se pasó un puntero, su objeto Person ahora tiene que preguntarse si esa otra parte de la aplicación cambió el valor de myAge!

Por lo tanto, NSNumber es inmutable, ya que es un objeto destinado a mantener un valor que se puede crear, recuperar y transmitir de forma gratuita en su aplicación como un valor, no como un objeto único.


Eiko hace un buen punto: un NSNumber representa un tipo de datos básico y no tiene sentido hacerlo mutable.

Es como tener un int i=0; y preguntando por qué 0 no es mutable. Y en OS X Lion x64, es exactamente eso para los enteros, porque los NSNumbers se implementan como punteros etiquetados , que son punteros que contienen datos en lugar de una dirección.

Ejemplo, digamos que queremos almacenar el entero 42 en un puntero. Podríamos crear un NSNumber y luego señalarlo, o podríamos reemplazar la dirección con un 42, en cuyo caso podemos omitir la creación de objetos. Pero, ¿cómo podemos saber si estamos tratando con un puntero común o un puntero etiquetado?

Un puntero x86 64 tiene 64 bits, pero solo usa 48 bits para la dirección del puntero. La razón es que 48 bits proporcionan un espacio de direcciones de 256 TB, que es mucho. Usar 64 bits sería un desperdicio porque requeriría más transistores en la CPU. Por lo tanto, el espacio de direcciones potencial es de 64 bits, pero las CPU actuales solo pueden usar 48. Debido a esto, los bits finales de un puntero son 0 porque no se utilizan. Utilizamos estos últimos bits para indicar que el puntero es un puntero etiquetado que representa un número entero con un número dado de bits.

Por lo tanto, un número de OS X NS que representa un número entero es literalmente solo un número entero, pero el tiempo de ejecución es capaz de detectarlo como un puntero etiquetado y presentarlo al usuario como una instancia común.

Para otros tipos numéricos, la implementación es mucho más complicada, como se ve en la contraparte gratuita de Core Foundation de CFNumber .


Supongo que es inmutable, al igual que otras clases (NSArray, NSString, etc.), porque los objetos inmutables son más fáciles de usar, compartir y transmitir en código enlazado. Véase la wikipedia .


Un ejemplo de subclasificación de números de NS

Nota: como se indica en la documentación, se debe implementar objCType y valor accessor del tipo implementado (intValue aquí).

Esto se hace aquí con un inicializador designado (-) inicial ... pero se puede hacer con el método (+).

@interface NSMutableNumber : NSNumber { int intValue; } @property const char *objCType; + (id) mutablenumberWithInt:(int)value; @end @implementation NSMutableNumber @synthesize objCType; + (id) mutablenumberWithInt:(int)value { return [[self alloc] initWithInt:value]; } - (id) initWithInt:(int)value { if (self=[super init]) { intValue=value; objCType="i"; } return self; } - (int)intValue { return intValue; } - (void)setInt:(int)value { intValue=value; } @end

Entonces

NSMutableNumber *mutn=[NSMutableNumber mutablenumberWithInt:2]; NSLog(@"%@/n", mutn); // return 2 [mutn setInt:4]; NSLog(@"%@/n", mutn); // return 4


Un número es un tipo de datos muy básico. Un número es solo eso, un número. Si lo mates, pasa que es otra cosa. Un número simplemente no puede cambiar.

Compare eso con datos más complejos, donde el objeto en sí todavía representa lo mismo.


Los números inmutables ahorran espacio. Supongamos que su programa crea muchos NSNumber s, y la mayoría de ellos son números pequeños como 0 o 1. Con números inmutables, solo necesita unos pocos objetos, uno para cada valor distinto. Con números mutables, tienes tantos objetos como números.

Los números inmutables son fáciles de compartir . Supongamos que envuelve un número primitivo (como int ) con un NSNumber . Con el NSNumber inmutable, el compilador siempre está seguro de que los valores coinciden, por lo que puede desenvolverlo y pasar el valor primitivo a la función que espera un valor primitivo. Con el NSNumber mutable, no puede estar seguro de que otro subproceso no cambió el valor y realmente tiene que desenvolverlo cada vez, o incluso pensar en la sincronización. Esto se vuelve más costoso si el valor se pasa más y más en las llamadas anidadas.

Los objetos inmutables tienen muchas otras propiedades útiles: son buenas claves hash, su vida útil y alcance son más fáciles de determinar, etc. Muchos lenguajes funcionales, por ejemplo, Erlang o XSLT, solo tienen estructuras de datos inmutables.