La conversión implícita de Objective-C pierde precisión de entero 'NSUInteger' (también conocido como 'unsigned long') a advertencia 'int'

187

Estoy trabajando en algunos ejercicios y tengo una advertencia que dice:

La conversión implícita pierde precisión entera: 'NSUInteger' (también conocido como 'unsigned long') a 'int'

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool {

        NSArray *myColors;

        int i;
        int count;

        myColors = @[@"Red", @"Green", @"Blue", @"Yellow"];

        count = myColors.count; //  <<< issue warning here

        for (i = 0; i < count; i++)

        NSLog (@"Element %i = %@", i, [myColors objectAtIndex: i]);
    }

    return 0;
}

Captura de pantalla

Chico mono
fuente

Respuestas:

470

El countmétodo de NSArraydevuelve un NSUInteger, y en la plataforma OS X de 64 bits

  • NSUIntegerse define como unsigned longy
  • unsigned long es un entero sin signo de 64 bits.
  • int es un entero de 32 bits.

Entonces, intes un tipo de datos "más pequeño" que NSUInteger, por lo tanto, la advertencia del compilador.

Consulte también NSUInteger en la "Referencia de tipos de datos de Foundation":

Al crear aplicaciones de 32 bits, NSUInteger es un entero sin signo de 32 bits. Una aplicación de 64 bits trata a NSUInteger como un entero sin signo de 64 bits.

Para corregir esa advertencia del compilador, puede declarar la countvariable local como

NSUInteger count;

o (si está seguro de que su matriz nunca contendrá más que 2^31-1elementos), agregue un reparto explícito:

int count = (int)[myColors count];
Martin R
fuente
19
Solo para agregar: voté por esta respuesta cuando recibí una carga de advertencias y errores de repente en mi proyecto Xcode 5. Mencionaste 64 bits que me llevaron a mirar mi configuración de compilación. Xcode lo cambió al modo de 64 bits que arrojó errores. Cambiarlo de nuevo a arvm7 los arregló a todos.
Robert J. Clegg
1
@Tander, ¿hay alguna diferencia de rendimiento entre compilar 64 bits y armv7?
Shaun Budhram
1
@ShaunBudhram Por lo que parece, no. No he visto ninguna diferencia. Solo hará una diferencia en las aplicaciones que usan mucho la CPU; los juegos, por ejemplo, verían un beneficio compilado para 64 bits.
Robert J. Clegg
77
"A partir del 1 de febrero de 2015, las nuevas aplicaciones iOS cargadas en la App Store deben incluir soporte de 64 bits ..." - Noticias y actualizaciones para desarrolladores de Apple, 20 de octubre de 2014
Pang
2
@JayprakashDubey: Apple no ve las advertencias de su compilador porque envía la aplicación compilada binaria a la App Store. Por lo tanto, su aplicación no puede ser rechazada debido a las advertencias del compilador. Por supuesto, debe corregirlos para que su aplicación funcione correctamente.
Martin R
24

Contrariamente a la respuesta de Martin, lanzar a int (o ignorar la advertencia) no siempre es seguro, incluso si sabe que su matriz no tiene más de 2 ^ 31-1 elementos. No cuando compila para 64 bits.

Por ejemplo:

NSArray *array = @[@"a", @"b", @"c"];

int i = (int) [array indexOfObject:@"d"];
// indexOfObject returned NSNotFound, which is NSIntegerMax, which is LONG_MAX in 64 bit.
// We cast this to int and got -1.
// But -1 != NSNotFound. Trouble ahead!

if (i == NSNotFound) {
    // thought we'd get here, but we don't
    NSLog(@"it's not here");
}
else {
    // this is what actually happens
    NSLog(@"it's here: %d", i);

    // **** crash horribly ****
    NSLog(@"the object is %@", array[i]);
}
Adrian
fuente
66
Tienes razón en que emitir el resultado indexOfObject:sería una mala idea. Mi respuesta fue para el código específico en la pregunta, y el countmétodo no puede regresar NSNotFound. No recomendé enviar a int o ignorar las advertencias en general. Lo siento si eso no estaba claro. De hecho, su código de muestra generaría una advertencia if (i == NSNotFound)si se compila para 64 bits, por lo que el problema no pasaría desapercibido.
Martin R
@Adrian: Si no te importa, ¿qué sugieres que haga el autor de la pregunta?
moonman239
@ moonman239 En general, usaría una variable del tipo correcto si es posible (la primera sugerencia de @ MartinR) en lugar de lanzar (su segunda). Como señala, el casting es seguro en este caso particular, pero creo que es un mal hábito, ya que puede tener consecuencias inesperadas (como en mi ejemplo). Publiqué porque me ha picado esta situación específica (aunque ese es un buen punto sobre la advertencia del == compilador, que debo haber pasado por alto).
Adrian
2
Creo que el conteo se usará con mucha más frecuencia que indexOfObject, e hinchar un bucle for con NSInteger simplemente para no tener un estilo de codificación "pobre" no tiene sentido. Debe observar únicamente indexOfObject y asegurarse de usar NSIntegers allí, todo lo que simplemente cuenta algo está bien como int, especialmente dentro de un enfoque de métodos
NikkyD
5

Cambiar clave en Proyecto> Configuración de compilación " typecheck llama a printf / scanf : NO "

Explicación: [Cómo funciona]

Verifique las llamadas a printf y scanf, etc., para asegurarse de que los argumentos proporcionados tengan tipos apropiados para la cadena de formato especificada, y que las conversiones especificadas en la cadena de formato tengan sentido.

Espero que funcione

Otra advertencia

la conversión implícita del objetivo c pierde precisión entera 'NSUInteger' (también conocido como 'largo sin signo') a 'int

Cambiar clave " conversión implícita a 32 bits Tipo> Depurar> * 64 arquitectura: No "

[ precaución: puede anular otra advertencia de conversión de arquitectura de 64 Bits] .

Darshit Shah
fuente
Si solo desea convertir su biblioteca de 32 bits en 64 bits, esta es una opción prometedora.
San
2

Hacer el casting explícito al "int" resuelve el problema en mi caso. Tuve el mismo problema. Entonces:

int count = (int)[myColors count];
Vladimir Despotovic
fuente
o se llama "implícito"? LOL :) En cualquier caso, funcionó.
Vladimir Despotovic