Xcode 6 iOS Creación de un marco Cocoa Touch – Problemas de architectures

Estoy tratando de hacer un marco dynamic para una aplicación de iOS. Gracias a la nueva versión de Xcode (6) podemos seleccionar un Marco de Trabajo Cocoa cuando creamos un nuevo proyecto y ya no hay necesidad de agregar un objective agregado, ejecutar un script y así crear uno. No tengo problemas cuando construyo el marco. Pero cuando bash usarlo dentro de una aplicación iOS, tengo algunos problemas de architecture.

ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (arm64): /Library/Frameworks/MyFramework.framework/MyFramework Undefined symbols for architecture arm64: "_OBJC_CLASS_$_MyFrameworkWebService", referenced from: objc-class-ref in AppDelegate.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation) ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (armv7): /Library/Frameworks/MyFramework.framework/MyFramework Undefined symbols for architecture armv7: "_OBJC_CLASS_$_MyFrameworkWebService", referenced from: objc-class-ref in AppDelegate.o ld: symbol(s) not found for architecture armv7 clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Bueno, he intentado cambiar la configuración del proyecto de marco y el objective (Arquitecturas y comstackción, Arquitectura válida únicamente y Arquitecturas válidas). He hecho lo mismo para el proyecto de la aplicación iOS pero nada funciona. Creo que hay algo que no entendí.

Por ejemplo, cuando construyo un marco para solo i386 (simulador de iOS) verifico con la línea de comando “xcrun lipo -info MyFramework”, tengo un problema que

ld: advertencia: ignorando el archivo /Library/Frameworks/MyFramework.framework/MyFramework, el archivo se creó para x86_64, que no es la architecture que se está vinculando (i386) …

Si alguien puede ayudarme a obtener un marco que funcione para todas las architectures iOS, incluidos los simuladores.

Basado en todas las respuestas, la publicación en raywenderlich.com y la esencia creada por Chris Conway, se me ocurrió esto .

Ejecutando los siguientes pasos pude construir un framework Cocoa Touch (incluyendo archivos Swift y Objective-C) que contiene todas las architectures tanto para el simulador como para el dispositivo:

  1. Cree un nuevo objective (Agregado) en el proyecto de su marco
  2. En “Crear fases”, selecciona “Agregar secuencia de comandos de ejecución” y copia el contenido de este archivo
  3. Seleccione el objective Agregado en el menú desplegable Selección de esquema
  4. Construya el objective para el esquema agregado

Espero eso ayude 🙂

ACTUALIZACIÓN: Se corrigió un error en la esencia donde las rutas en el paso # 3 eran incorrectas. Gracias a Tokuriku !!

ACTUALIZACIÓN En Xcode 7 y 8, haga clic en Archivo> Nuevo> Destino … y seleccione “Otro” grupo para seleccionar el objective Agregado

Pruebe los siguientes pasos para crear un espacio de trabajo que contenga un proyecto de marco y un proyecto de aplicación.

Espacio de trabajo:

  • Crea un espacio de trabajo.

Proyecto de marco:

  • Cree un proyecto iOS Cocoa touch Framework dentro de Workspace.
  • Agregue una clase simple de Objective C MyClass (header .h y archivo de implementación .m) y cree un método – (void) saludos .
  • Vaya a Project Build Phases > Headers > Mueva MyClass.h de Project a Public .
  • Cambie el esquema al proyecto marco y elija el simulador iOS , luego compile. (Elija Dispositivo iOS si la aplicación que integra este marco se ejecuta en el dispositivo. Continuaré usando el simulador en este ejemplo)
  • No debe tener problemas para comstackr, la construcción del marco se encuentra en su directorio de Datos Derivados que puede encontrar en el Organizador .

Proyecto de aplicación:

  • Cree una aplicación Swift Single View dentro de Workspace.
  • Arrastre sobre la comstackción del marco del simulador de iOS (se encuentra en Debug-iphonesimulator o Release-iphonesimulator ) en su proyecto.
  • Cree un encabezado puente para exponer los métodos de la clase Objective C a Swift.
  • Importe MyClass.h en el archivo de encabezado de puente.
  • Tenga en cuenta que si no se encuentra la definición de MyClass, entonces agregue la ruta de Encabezados de marco de las Rutas de búsqueda de encabezado de Configuración de comstackción.
  • Crea una instancia de MyClass en viewDidLoad de ViewController.swift , luego llama a saludos .
  • Agregar framework a Target> Binarios incrustados
  • Cambia el esquema al proyecto de la aplicación y elige el simulador iOS , luego comstack.
  • Debería poder ver los mensajes de saludo.

Tenga en cuenta que el ejemplo anterior muestra cómo crear una aplicación que se ejecuta en el simulador . Si necesita crear una biblioteca estática universal que se ejecute tanto en el simulador como en los dispositivos , los pasos generales son:

  • Crear biblioteca para el simulador
  • Crear biblioteca para el dispositivo
  • Combínalos usando lipo

Hay buenas referencias en la web sobre esto, aquí por ejemplo.

Crear un binario universal para el framework: navegue hasta el directorio de datos derivados del framework y / Build / Products , el siguiente comando debería ayudarlo a crear un binario universal en el directorio Products :

 lipo -create -output "framework-test-01-universal" "Debug-iphonesimulator/framework-test-01.framework/framework-test-01" "Debug-iphoneos/framework-test-01.framework/framework-test-01" 

Tenga en cuenta que framework-test-01 es mi nombre de proyecto de framework.

Aquí hay unos pasos para crear el marco gordo (universal):

  1. Establezca ONLY_ACTIVE_ARCH=NO en la Build Settings en su proyecto.

    • Crear biblioteca para el simulador
    • Crear biblioteca para el dispositivo
  2. Abra en la carpeta de Products consola para su marco (puede abrirlo desde la carpeta de Open Framework y desde allí desde el cd .. )

enter image description hereenter image description here

  1. Ejecute este script desde la carpeta Products . Crea un marco gordo en esta carpeta. (o hágalo manualmente como se explica a continuación en 4. 5. )

     framework_name="${$(basename $(find ./Debug-iphoneos -type d -name '*.framework' -maxdepth 1))%.*}" && \ cp -R Debug-iphoneos/$framework_name.framework ./$framework_name.framework && \ lipo -create -output "$framework_name.framework/$framework_name" "Debug-iphonesimulator/$framework_name.framework/$framework_name" "Debug-iphoneos/$framework_name.framework/$framework_name" 

O:

  1. Combine estos 2 marcos utilizando lipo con este script (reemplace YourFrameworkName por el nombre de su Framework)

     lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName" 
  2. Reemplace con uno nuevo binario de los marcos existentes:

     cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName 

  1. Profit: ./YourFrameworkName.framework – ¡ es un binario gordo listo para usar! ¡Puedes importarlo a tu proyecto!

Para el proyecto, eso no está en xcworkspace -es:

También puede intentar utilizar esta idea. Pero parece que no funciona para proyectos en espacios de trabajo.

La forma en que lo hice es similar a vladof, pero espero que sea un poco más simple. Hice el marco un subproyecto del proyecto de la aplicación.

Proyecto de marco

  • Crea un nuevo iOS Cocoa Touch Framework. Llámalo MyLib. Esto creará un solo MyLib.h
  • Agregue una clase simple Cocoa Touch Obj-C, MyClass (.h & .m) y en la implementación de .m, cree un método que devuelva una cadena, – (NSString *) saludos;
  • En MyLib.h, agrégalo cerca de la parte inferior, #import “MyClass.h”
  • En la sección Crear fases / encabezados del objective, mueva MyClass.h de la sección Proyecto a la sección Público.
  • Haz una comstackción (cmd-B)
  • Cierre el proyecto

Proyecto de aplicación

  • Cree un nuevo proyecto de aplicación de vista única, Swift u Obj-C. Llámalo MyApp.
  • Desde el Finder, arrastre su archivo de proyecto MyLib a la sección del organizador de la izquierda de su ventana MyApp y asegúrese de que la línea de inserción esté justo debajo de MyApp. Esto hace que MyLib sea un subproyecto de MyApp. (Todavía se puede usar de la misma manera en otros proyectos)
  • Haga clic en MyApp en el organizador y luego seleccione el objective MyApp y seleccione Build Phases.
  • En Dependencias de destino, haga clic en el signo + y agregue MyLib.
  • En Enlace con bibliotecas, haga clic en el signo + y agregue MyLib.framework.

Para una aplicación Obj-C

  • En ViewController.m, agregue # import
  • En viewDidLoad, agregue las siguientes líneas:
  • MyLib * x = [[MyLib alloc] init];
  • NSLog (@ “% @”, x.greetings);
  • Ejecute el proyecto y debería ver el mensaje en la ventana de depuración. –

Para una aplicación Swift

  • En ViewController.swift, agregue importar MyLib
  • en viewDidLoad, agregue las siguientes líneas:
  • var x: MyLib = MyLib ()
  • println (“(x.greetings ())” –

Al hacerlo de esta manera, la aplicación depende del marco, por lo que si realiza un cambio en las clases de marco, no tiene que cambiar los objectives para construir el marco por separado, primero comstackrá el marco primero y luego la aplicación.

Cambié un poco el guión de alguien para admitir todas las architectures del simulador:

 UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" # Step 1. Build Device and Simulator versions xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator VALID_ARCHS="x86_64 i386" BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build # Step 2. Copy the framework structure to the universal folder cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}" # Step 4. Convenience step to copy the framework to the project's directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 5. Delete temporary build directory in the project's directory rm -rf "${PROJECT_DIR}/build" # Step 6. Convenience step to open the project's directory in Finder open "${PROJECT_DIR}" 

Un viejo video que hice desde el enlace anterior ya no está disponible.

Cómo crear un marco de Cocoa Touch usando Xcode 6

Pocos puntos adicionales en torno al enfoque compartido por vladof son más aplicables a Frameworks basados ​​rápidamente

  1. El script en el enlace asociado necesita modificación para copiar todos los archivos de iphonesimulator y iphoneos ya que el swift tiene archivos comstackdos por separado para arm y i386
  2. Asegúrese de tener ARCHS = “x86_64” ONLY_ACTIVE_ARCH = NO en la comstackción para iphonesimulator para evitar problemas con el enlazador para el simulador
  3. Asegúrese de que su interfaz / clase amplíe NSObject, de lo contrario se encontrará con problemas cuando intente usar el código rápidamente (se quejará de que no pueda crear objetos usando ().

¡Finalmente, lo tengo para mí! Y lo siento por el gran marco amarillo, no tengo idea de cómo formatearlo mejor.

La solución vino de Claudio Romandi, pero el guión vinculado tiene un pequeño problema. No puedo hacer ningún comentario sobre su publicación porque necesito 50 de reputación, así que me queda poco para copiar su publicación para tener una solución completa.

  1. Cree un nuevo objective (Agregado) en su Proyecto Marco
  2. Seleccione el agregado en el espacio de trabajo y agregue una “Nueva fase de ejecución de script”
  3. Pon el siguiente código en él:

     #!/bin/sh UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal # make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" # Step 1. Build Device and Simulator versions xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build # Step 2. Copy the framework structure (from iphoneos build) to the universal folder cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/" # Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directory cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule" # Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}" # Step 5. Convenience step to copy the framework to the project's directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}" # Step 6. Convenience step to open the project's directory in Finder open "${PROJECT_DIR}" 
  4. Seleccione el agregado en el menú desplegable de selección de esquema

  5. ¡Construye, ya terminaste!

El problema era que el directorio del simulador apuntaba a un directorio no existente, cambiando “Framework” a “$ {PROJECT_NAME}” en 2 lugares lo hizo 🙂

Lo siento, dejé este tema abierto durante tanto tiempo … Algunos de ustedes han respondido correctamente a mi pregunta. Cuando escribí esta pregunta que no capté, había dos cortes en un marco completo (también llamado gordo) (listo para usar). Uno para los dispositivos iOS y otro para el simulador. Cuando descubrí que hice una secuencia de comandos con el comando lipo para fusionar las dos partes y obtener automáticamente un marco completo.