Pruebas de la unidad Xcode: error de enlace cuando se construye solo para dispositivo

Mi unidad de aplicaciones testing la compilation y la testing cuando se ejecuta en el simulador, pero falla con un error de vinculación al crear y probar el dispositivo.

En mi objective de aplicación, he configurado las siguientes configuraciones de compilation:

DEPLOYMENT_POSTPROCESSING = NO GCC_SYMBOLS_PRIVATE_EXTERN = NO 

En la testing de mi unidad, he configurado las siguientes configuraciones de compilation:

 BUNDLE_LOADER = $(BUILT_PRODUCTS_DIR)/<app name>.app/<app> TEST_HOST = $(BUNDLE_LOADER) 

El error del linker es:

 Undefined symbols for architecture armv7s: "_<An NSString * const>", referenced from: -[UnitTestClassA setUp] in UnitTestClassA.o "_<Another NSString * const>", referenced from: -[UnitTestClassB helperMethod:] in UnitTestClassB.o -[UnitTestClassB anotherHelperMethod:] in UnitTestClassB.o ld: symbol(s) not found for architecture armv7s clang: error: linker command failed with exit code 1 (use -v to see invocation) 

… Tengo "continuar después de errores de construcción" activado en las preferences de Xcode, pero no recibo una tonelada de errores de linker que se quejan de NSString * const's. Si estoy haciendo algo mal, entonces esperaría más errores de enlace que el puñado que recibo ya que uso constantes de cadena en todo mi código de producción.

Estoy creando mis constantes de cadena como esta:

Archivo .h …

 extern NSString * const ReallyGoodString; 

file .m …

 NSString * const ReallyGoodString = @"This string is great!"; 

… el file .m es código de producción y parte de mi objective de aplicación, por lo que no tengo que vincularlo en el package de testing de unidad.

¿Entonces, qué está pasando aquí? ¿Por qué esto funciona bien en el simulador y no en el dispositivo?

Publicé un proyecto de ejemplo para Github que ilustra el problema. Puede ver en el proyecto de ejemplo que este problema es incoherente: algunos símbolos vinculan bien a otros que no lo hacen.

Cuando el vinculador está creando el ejecutable Linker-Error , descarta FHKViewControllerThisSymbolWontLink porque nada en el ejecutable lo usa. El linker no sabe que debe mantener el símbolo alnetworkingedor para que lo use el package de testing de la unidad (que se carga dinámicamente en time de ejecución).

Puede decirle al vinculador que no quite el símbolo no utilizado etiquetándolo con el atributo used , así:

 NSString * const FHKViewControllerThisSymbolWontLink __attribute__((used)) = @"name"; 

Tendrá que hacer eso por cada símbolo que defina que no sea utilizado por el ejecutable principal pero que sea utilizado por el set de testings.

Esto es probablemente debido a que tiene símbolos que están siendo utilizados por su set de testings que no son utilizados por la aplicación principal y está habilitada la eliminación de código muerto . Puede deshabilitar la opción de eliminación de código muerto de acuerdo con la configuration. Solucioné un problema similar para permitir que las testings se ejecuten en mi dispositivo al voltear la opción Solo para comstackciones de debugging.

Algunas posibilidades:

  1. Importa un encabezado y no se vincula con la biblioteca correcta. Esto es común, especialmente para los encabezados de bibliotecas como QuartzCore, ya que no está incluido en los proyectos por defecto. Resolver:

    A. Agregue las bibliotecas correctas en la sección Vincular binary con bibliotecas de las Fases de compilation.

  2. Copias files en tu proyecto, pero se olvidó de verificar el destino al que agregar los files. Resolver:

    A. Abra las Fases de compilation para el objective correcto, expanda Orígenes de compilation y agregue los files .m faltantes.

  3. Si está utilizando testings de lógica, no son compatibles con dispositivos iOS, sino solo en el simulador. Sin embargo, las testings de aplicación funcionan en dispositivos. Documentos para eso:

iOS: aunque Xcode puede ejecutar testings de unidades lógicas y de aplicaciones en simuladores, Xcode no puede ejecutar testings de unidades lógicas en dispositivos iOS. Por lo tanto, si incluye y tiene activos ambos types de testings unitarias en un esquema, no podrá usar ese esquema para ejecutar testings unitarias en dispositivos iOS.

Una vez tuve un problema similar y la solución fue tan simple como limpiar el proyecto, supongo que ya lo intentaste, pero quizás no. Probablemente lo intentaría. Simplemente vaya a "Producto" -> "Limpiar" en la barra de navigation superior, o use el atajo: "shift" "command" "K"

(Habría escrito esto como un comentario y no una respuesta, ya que no es más que una simple sugerencia. Pero no tengo suficientes puntos para comentar, lo siento).