¿Puedo mezclar Swift con C ++? Al igual que los archivos Objective-C .mm


131

Acabo de cambiar mis archivos .m a .mm y uso C ++. ¿Hay alguna manera de hacer lo mismo con Swift?

Respuestas:


111

No. Cuando cambia de .m a .mm, en realidad está cambiando de Objective-C a un lenguaje diferente (que tiene muchas diferencias sutiles) llamado Objective-C ++. Entonces realmente no estás usando C ++; está utilizando Objective-C ++ que acepta la mayoría de C ++ como entrada (de la misma manera que C ++ acepta la mayoría pero no toda C como entrada). Cuando digo que no es C ++, considere un archivo C ++ que incluya una variable llamada nil(que es legal C ++) y luego intente compilarlo como Objective-C ++.

Swift no tiene la misma relación. No es un superconjunto de C o C ++, y no se puede usar directamente en un .swiftarchivo.

"Usar Swift con cacao y Objective-C" también nos dice:

No puede importar código C ++ directamente en Swift. En su lugar, cree un contenedor Objective-C o C para el código C ++.


93
Bastante molesto en realidad: todos nosotros con aplicaciones Cocoa que incorporan bases de código C / C ++ ahora tenemos que mantener proyectos escritos en 3 idiomas ...
Jay

66
Sugiero que Objective-c ++ no es un lenguaje diferente, pero una combinación de c ++ y Objective-c diferencia es sutil pero todavía está allí
amar

1
¿Cómo es "nulo" legal C ++? No existe tal cosa (al menos en c ++ estándar) Proporcione otro ejemplo
rewolf

3
Pero con ObjC puedes simplemente ir a .mmtus archivos y estar (casi) listo. No es así con Swift.
chakrit

66
@rewolf, creo que se refiere a una variable llamada nil, comoint nil
Luke

165

La confusión puede venir de la suposición de que simplemente cambiar una extensión de archivo de .ma .mmes todo lo que necesita para unir los idiomas, cuando, en realidad, no hace nada de eso. No es lo .mmque causa fricción .cpp, es el .hencabezado el que no debe ser un C++encabezado.


Mismo proyecto: sí.

En el mismo proyecto, puede mezclar felizmente C , C ++ , Objective-C , Objective C ++ , Swift e incluso Assembly .

  1. ...Bridging-Header.h: expones C , Objective-C y Objective-C ++ a Swift usando este puente
  2. <ProductModuleName>-Swift.h: Expone de forma automática sus Swift clases marcados con @objca Objective-C
  3. .h: esta es la parte difícil, ya que se usan de manera ambigua para todos los sabores de C , ++ o no, objetivo o no. Cuando a .hno contiene una sola palabra clave de C ++ , como class, se puede agregar a ...Bridging-Header.h, y expondrá cualquier función que corresponda .c o .cpp funcionalidades que declara. De lo contrario, ese encabezado debe estar envuelto en una API pura de C o Objective-C .

Mismo archivo: No.

En el mismo archivo, no puede mezclar los 5. En el mismo archivo fuente :

  1. .swift: no puedes mezclar Swift con nada
  2. .m: Usted puede mezclar Objective-C con C . ( @Vinzzz )
  3. .mm: puedes mezclar Objective-C con C ++ . Este puente es Objective-C ++ . ( @Vinzzz ).
  4. .c: puro C
  5. .cpp: puedes mezclar C ++ y ensamblaje ( @Vality )
  6. .h: ubicuo y ambiguo C , C ++ , Objective-C u Objective-C ++ , por lo que la respuesta es que depende.

Referencias


1
Corrección: en el mismo archivo fuente .m , Objective-C es un estricto superconjunto de C, PUEDES mezclar Objective-C y C ...
Vinzzz

1
No hay problema, ni siquiera me importa el crédito, siempre que la respuesta sea la correcta;) Por cierto, .mm es para mezclar Objective-C y C ++ (C y C ++ son dos cosas diferentes, a pesar del nombre )
Vinzzz

1
Mencionaría que, a diferencia del objetivo C, C ++ no es un superconjunto de C, por lo que no puede mezclar C y C ++ en un archivo .cpp. Solo C ++ y ensamblaje.
Vality

1
En caso de que alguien encuentre que esta respuesta bien detallada no ayuda cuando se intenta exponer archivos Swift en su archivo Objective-C / C ++ (Xcode se queja de que no se encuentra el archivo de encabezado Swift). Descubrí que tenía que importar "ProductName / ProductModuleName-Swift.h" en mi archivo fuente Objective-C / C ++. Encontré esto algo enterrado en: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
AeroBuffalo

Buen punto. Para un proyecto de trabajo que combine estos idiomas, eche un vistazo a stackoverflow.com/a/32546879/218152 .
SwiftArchitect el

72

Escribí un proyecto simple de Xcode 6 que muestra cómo mezclar C ++, Objective C y código Swift:

https://github.com/romitagl/shared/tree/master/C-ObjC-Swift/Performance_Console

En particular, el ejemplo llama a un objetivo C y una función C ++ de Swift.

La clave es crear un encabezado compartido Project-Bridging-Header.h y colocar los encabezados de Objective C allí.

Descargue el proyecto como un ejemplo completo.


Gracias por esto Gian!
Jason Elwood

Gracias por este ejemplo, pero si quiero mover el #import "CPlusPlus.h" de ObjCtoCPlusPlus.mm al archivo ObjCtoCPlusPlus.h, el compilador devuelve este error: <desconocido>: 0: error: no se pudo importar el encabezado de puente ' /Users/Ale/Downloads/shared-master/C-ObjC-Swift/Performance_Console/Performance_Console/Performance_Console-Bridging-Header.h '¿es posible mover esta importación al archivo de encabezado?
Alessandro Pirovano

@API: No, te estás perdiendo el punto. ObjCtoCPlusPlus.h/ `` .mm` existe con el único propósito de proporcionar una interfaz Ob-C al código C ++; es el puente, que es un componente necesario aquí. Deje las inclusiones donde están y agregue un método en los ObjCtoCPlusPlus.…archivos para cada método C ++ al que necesite acceder. Haría
Slipp D. Thompson el

Descargué tu ejemplo y es fantástico para la función ESTÁTICA que ofrece la clase como ejemplo, pero no puedo adaptar el ejemplo para que una función no estática adicional se use desde afuera ... ¿También es posible? (Hice mi tarea de C ++ hace décadas ... no soy el lápiz más afilado de la caja en este momento)
Isaac

31

También puede omitir el archivo Objective-C en el medio. Simplemente agregue un archivo de encabezado C con un archivo fuente .cpp. Tenga solo declaraciones C en el archivo de encabezado e incluya cualquier código C ++ en el archivo fuente. Luego incluya el archivo de encabezado C en ** - Bridging-Header.h.

El siguiente ejemplo devuelve un puntero a un objeto C ++ (struct Foo) para que Swift pueda almacenar en un COpaquePointer en lugar de tener struct Foo definido en el espacio global.

Archivo Foo.h (visto por Swift - incluido en el archivo puente)

#ifndef FOO_H
#define FOO_H

// Strictly C code here.
// 'struct Foo' is opaque (the compiler has no info about it except that 
// it's a struct we store addresses (pointers) to it.
struct Foo* foo_create();
void foo_destroy(struct Foo* foo);

#endif

Archivo fuente interno Foo.cpp (no visto por Swift):

extern "C"
{
#include "Foo.h"
}
#include <vector>

using namespace std;

// C++ code is fine here. Can add methods, constructors, destructors, C++ data members, etc.
struct Foo
{
   vector<int> data;
};

struct Foo* foo_create()
{
   return new Foo;
}

void foo_destroy(struct Foo* foo)
{
    delete foo;
}

1
Esta respuesta merece mucho más votos a favor. Realmente util.
rsp1984

Esta es la primera vez que veo extern "C"envolver el encabezado en el lugar donde está incluido en lugar de #ifdef'editado en el archivo de encabezado. ¡Brillante!
dcow

27

Acabo de hacer un pequeño proyecto de ejemplo usando Swift, Objective-C y C ++. Es una demostración de cómo usar la costura de OpenCV en iOS. La API de OpenCV es C ++, por lo que no podemos hablar con ella directamente desde Swift. Utilizo una clase de contenedor pequeña cuyo archivo de implementación es Objective-C ++. El archivo de encabezado está limpio Objective-C, por lo que Swift puede hablar con esto directamente. Debe tener cuidado de no importar indirectamente ningún archivo C ++ - ish en los encabezados con los que Swift interactúa.

El proyecto está aquí: https://github.com/foundry/OpenCVSwiftStitch


Creo que esto responde a un problema que encontré hoy tratando de usar una biblioteca de terceros KudanCV con Swift. Mi encabezado de puente importa su archivo .h que contiene importaciones a <memory> <strings> y <vectors> que supongo que son de bibliotecas o archivos de C ++, como resultado mi código Swift no se compilará. Estaría agradecido si alguien pudiera decirme si hay una forma de evitar esto ... o si tengo que reescribir todo mi código en Objective-C
Rocket Garden el

1
@RocketGarden: el archivo de encabezado KudanCV es C ++. Podría escribir un contenedor que funcione de la misma manera que mi clase de contenedor de ejemplo. O reescribe aquellas partes de tu aplicación que necesitan hablar con KudanCV en Objective-C ++ (con encabezados Objective-C). No necesitaría reescribir aquellas partes de su proyecto que no están relacionadas con KudanCV.
fundición

Gracias por eso, me di cuenta unos 5 minutos más tarde, pero es útil tenerlo registrado para otros.
Rocket Garden el

13

Aquí está mi intento de una herramienta de clang para automatizar la comunicación C ++ / swift. Puede instanciar clases de C ++ de swift, heredar de la clase de C ++ e incluso anular métodos virtuales en swift.
Analizará la clase de C ++ que desea exportar a swift y generará el puente Objective-C / Objective-C ++ automáticamente.

https://github.com/sandym/swiftpp




4

No, no en un solo archivo.

Sin embargo, puede usar C ++ en proyectos Swift sin necesidad de una biblioteca o marco estático. Como otros han dicho, la clave es hacer un encabezado de puente Objective-C que # incluya encabezados C ++ compatibles con C que estén marcados como C compatibles con el truco externo "C" {} .

Video tutorial: https://www.youtube.com/watch?v=0x6JbiphNS4


2

Otras respuestas son ligeramente inexactas. En realidad, puede mezclar Swift y [Objective-] C [++] en el mismo archivo, aunque no del modo esperado.

Este archivo (c.swift) se compila en un ejecutable válido con ambos swiftc c.swiftyclang -x objective-c c.swift

/* /* */
#if 0
// */
import Foundation
print("Hello from Swift!")
/* /* */
#endif
#include <stdio.h>
int main()
{
    puts("Hello from C!");
    return 0;
}
// */

Su código de muestra está en C, no en C ++. Mejor ve con un ejemplo <iostream> en mi humilde opinión.
kakyo

2

Un truco (de muchos) es que

Necesita un encabezado separado para su archivo obj-c ++ puente ...

No puede simplemente lanzar @interface y @implementation en el mismo archivo .mm como se suele hacer normalmente.

Entonces, en su archivo de encabezado puente tiene

#import "Linkage.hpp"

Linkage.hpp tiene la @interface para Linkage y Linkage.mm tiene la @implementation para .mm

Y entonces

... en realidad no #incluye "yourCpp.hpp" en Linkage.hpp.

Solo coloca #include "yourCpp.hpp"el archivo Linkage.mm, no el archivo Linkage.hpp.

En muchos ejemplos / tutoriales en línea, el escritor simplemente coloca la @interface y la @implementation en el mismo archivo .mm, como suele ocurrir.

Eso funcionará en ejemplos de puente cpp muy simples, pero,

El problema es:

si su yourCpp.hpp tiene alguna característica de c ++ que seguramente tendrá (como la primera línea #include <something>), entonces el proceso fallará.

Pero si simplemente no tiene el archivo de encabezado#include "yourCpp.hpp" Linkage (está bien tenerlo en el archivo .mm, obviamente necesitará): funciona.

De nuevo, esto es lamentablemente solo un consejo en todo el proceso.


1

En caso de que esto sea útil para alguien, también tengo un breve tutorial sobre cómo llamar a una biblioteca estática simple de C ++ desde una utilidad trivial de línea de comandos de Swift. Esta es una pieza de código de prueba de concepto realmente básica.

No hay Objective-C involucrado, solo Swift y C ++. El código en una biblioteca de C ++ es llamado por un contenedor de C ++ que implementa una función con enlace externo "C". Luego se hace referencia a esa función en el encabezado de puente y se llama desde Swift.

Ver http://www.swiftprogrammer.info/swift_call_cpp.html


1

Estoy proporcionando un enlace a SE-0038 en el recurso oficial, descrito como Esto mantiene propuestas de cambios y mejoras visibles para el usuario al Lenguaje de programación Swift.

El estado actual es que esta es la solicitud de función que se ha aceptado pero aún no está programada.

Este enlace está destinado a dirigir a cualquiera que busque esta función en la dirección correcta

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.