Cómo Swift distingue el simulador de un dispositivo real: análisis completo

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Cómo Swift distingue el simulador de un dispositivo real? Análisis completo bajo el capó

\n\n

Cada desarrollador iOS se ha enfrentado al menos una vez a una situación en la que el código funciona perfectamente en el simulador, pero falla en un dispositivo real. O viceversa: una función que utiliza la cámara o el acelerómetro no está disponible en el simulador. En esos momentos, es vital saber distinguir dónde se ejecuta la aplicación: en un iPhone/iPad físico o en el entorno virtual de Xcode. Este tema es un verdadero éxito en Stack Overflow (¡miles de visitas!), y hoy lo analizaremos a fondo. No solo aprenderá soluciones listas para usar, sino que también comprenderá cómo funcionan a nivel de compilador y preprocesador.

\n\n

¿Por qué es necesario?

\n

El simulador es una herramienta potente, pero no emula todo el hardware. Por ejemplo, no tendrá acceso a:

\n
    \n
  • Cámara (solo emulación a través de la cámara web del Mac)
  • \n
  • Acelerómetro y giroscopio
  • \n
  • Módulo de llamadas real
  • \n
  • Face ID (solo en simulador con T2/M1)
  • \n
  • Chip Secure Enclave
  • \n
\n

Además, las arquitecturas de los procesadores son diferentes: en un dispositivo real es ARM64, mientras que en el simulador (en Mac con Intel) es x86_64. Incluso en Apple Silicon, el simulador funciona a través de Rosetta 2, lo que introduce sus propios matices. Precisamente para estos casos necesitamos la verificación de simulador en Swift.

\n\n

Método clásico: TARGET_OS_SIMULATOR

\n

El método más popular y recomendado por Apple es usar la directiva de preprocesador TARGET_OS_SIMULATOR. Está definida en el archivo de cabecera TargetConditionals.h, que se incluye automáticamente en cada proyecto Swift a través del módulo Darwin.

\n\n

Así es como se ve el código estándar:

\n\n
#if targetEnvironment(simulator)\n    print("Ejecutándose en el simulador")\n    // Aquí se puede emular el comportamiento de la cámara o el GPS\n#else\n    print("Ejecutándose en un dispositivo real")\n    // Cámara real, GPS real\n#endif
\n\n

Simple, elegante, funciona. Pero profundicemos: ¿qué sucede realmente cuando el compilador ve esta construcción?

\n\n

Bajo el capó: cómo funciona targetEnvironment

\n

En Swift, la construcción #if targetEnvironment(simulator) no es magia, sino el resultado del trabajo del preprocesador. Cuando Xcode compila el proyecto para el simulador, agrega una bandera especial del compilador -DTARGET_OS_SIMULATOR=1. En consecuencia, para un dispositivo real, esta bandera es 0 o está ausente.

\n\n

Aquí está la cadena de transformaciones:

\n
    \n
  1. Xcode determina hacia dónde se dirige la compilación (esquema de compilación)
  2. \n
  3. Si se selecciona el simulador, se agrega -D TARGET_OS_SIMULATOR a OTHER_SWIFT_FLAGS
  4. \n
  5. El compilador Swift ve esta constante y procesa el bloque #if
  6. \n
  7. Todo el código dentro del bloque #else (para dispositivo real) se elimina del binario
  8. \n
\n\n

Esto significa que dicho código no solo se ejecuta en tiempo de ejecución, sino que se compila de manera diferente para diferentes plataformas. Obtiene dos archivos binarios diferentes, y en cada uno de ellos no hay código innecesario. ¡Ahorro de espacio y velocidad!

\n\n

Método alternativo: verificación de arquitectura

\n

Antes de la aparición de targetEnvironment, los desarrolladores usaban un truco ingenioso con las banderas de arquitectura. Todavía funciona y, a veces, es útil para la compatibilidad con versiones anteriores.

\n\n
#if arch(x86_64) || arch(i386)\n    print("Simulador (Intel Mac)")\n#elseif arch(arm64)\n    print("Dispositivo real o simulador en Apple Silicon")\n#endif
\n\n

¡Pero aquí hay un problema! En Mac con Apple Silicon (M1, M2, M3), el simulador también funciona en ARM64. Por lo tanto, simplemente verificar arch(arm64) no es suficiente: será verdadero tanto para un iPhone real como para el simulador en M1. Precisamente por eso Apple introdujo targetEnvironment(simulator): está diseñado específicamente para esta tarea.

\n\n

Particularidades de trabajar en Apple Silicon

\n

Desde 2020, cuando se lanzaron los Mac con ARM, c

Blogs

Book Recommendations