Могу ли я смешать Swift с C ++? Как Objective - C .mm файлы

117

Я только что изменил свои .m файлы на .mm и использовал С++. Есть ли способ сделать то же самое с Swift?

Теги:

12 ответов

101
Лучший ответ

Нет. Когда вы переключаетесь с .m на .mm, вы фактически переключаетесь с Objective-C на другой язык (который имеет много тонких различий) под названием Objective-C ++. Таким образом, вы не используете С++; вы используете Objective-C ++, который принимает большинство С++ в качестве входных данных (таким же образом, что С++ принимает большинство, но не все C в качестве входных данных). Когда я говорю это не совсем С++, рассмотрим файл С++, который включает переменную с именем nil (которая является законной С++), а затем попытайтесь скомпилировать ее как Objective-C ++.

Swift не имеет одинаковых отношений. Это не надмножество C или С++, и вы не можете напрямую использовать его в файле .swift.

"Использование Swift с Cocoa и Objective-C" также сообщает нам:

Вы не можете импортировать код С++ непосредственно в Swift. Вместо этого создайте оболочку Objective-C или C для кода С++.

  • 1
    Так что нет встроенного C / C ++. ... Хммм
  • 0
    Интригующий нюанс.
Показать ещё 14 комментариев
145

Путаница может исходить из предположения, что простое изменение расширения файла от .m до .mm - это все, что вам нужно, чтобы соединить языки, когда на самом деле он ничего не делает. Не .mm вызывает трение с .cpp, это заголовок .h, который должен положительно не быть заголовком C++.


Тот же проект: Да.

В том же проекте вы можете с радостью смешать C, С++, Objective-C, Objective С++, Swift и даже Assembly.

  • ...Bridging-Header.h: выставляете C, Objective-C и Objective-C ++ в Swift используя этот мост
  • <ProductModuleName>-Swift.h: автоматически выделяет классы Swift с @objc до Objective-C
  • .h: это сложная часть, поскольку они неоднозначно используются для всех ароматов C, ++ или нет, Цель или нет. Если .h не содержит одного ключевого слова С++, например class, его можно добавить в ...Bridging-Header.h и выставить любую функцию, соответствующую .c или .cpp, которые он объявляет. В противном случае этот заголовок должен быть обернут либо чистым C, либо Objective-C.

Тот же файл: Нет.

В том же файле вы не можете смешивать все 5. В том же исходном файле:

  • .swift: вы не можете смешивать Swift с чем-либо
  • .m: вы можете смешивать Objective-C с C. (@Vinzzz)
  • .mm: вы можете смешивать Objective-C с С++. Этот мост Objective-C ++. (@Vinzzz).
  • .c: pure C
  • .cpp: вы можете смешивать С++ и Сборка (@Vality)
  • .h: вездесущий и двусмысленный C, С++, Objective-C или Objective-C ++, поэтому ответ зависит от этого.

Ссылки

  • 1
    Исправление: В том же исходном файле .m , Objective-C является строгим надмножеством C, вы МОЖЕТЕ смешать Objective-C и C ...
  • 1
    Нет проблем, мне даже наплевать на кредит, если ответ правильный;) Кстати, .mm для смешивания Objective-C и C ++ (C и C ++ - две разные вещи, несмотря на название )
Показать ещё 5 комментариев
72

Я написал простой проект Xcode 6, который показывает, как смешивать код С++, Objective C и Swift:

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

В частности, пример вызывает функцию Objective C и С++ из Swift.

Ключом является создание общего заголовка Project-Bridging-Header.h и размещение там заголовков Objective C.

Пожалуйста, загрузите проект в качестве полного примера.

  • 0
    Спасибо за это Джиан!
  • 0
    Спасибо за этот пример, но если я хочу переместить #import "CPlusPlus.h" из файла ObjCtoCPlusPlus.mm в файл ObjCtoCPlusPlus.h, компилятор вернет эту ошибку: <unknown>: 0: error: не удалось импортировать заголовок моста ' /Users/Ale/Downloads/shared-master/C-ObjC-Swift/Performance_Console/Performance_Console/Performance_Console-Bridging-Header.h 'возможно ли переместить этот импорт в файл заголовка?
Показать ещё 1 комментарий
27

Я только что сделал небольшой проект с использованием Swift, Objective-C и С++. Это демонстрация того, как использовать строчку OpenCV в iOS. API OpenCV - это С++, поэтому мы не можем напрямую разговаривать с ним из Swift. Я использую небольшой класс-оболочку, файл реализации Objective-C ++. Файл заголовка чистый Objective-C, поэтому Swift может напрямую об этом поговорить. Вы должны заботиться о том, чтобы не косвенно импортировать любые файлы С++ - ish в заголовки, с которыми Swift взаимодействует.

Проект находится здесь: https://github.com/foundry/OpenCVSwiftStitch

  • 0
    Я думаю, что это решает проблему, с которой я столкнулся сегодня, пытаясь использовать стороннюю библиотеку KudanCV со Swift. Мой соединительный заголовок импортирует их файл .h, который содержит импорт в <memory> <strings> и <vectors>, который, как я полагаю, взят из библиотек или файлов C ++, в результате мой код Swift не будет компилироваться. Буду признателен, если кто-нибудь скажет мне, есть ли способ обойти это ... или если мне придется переписать весь мой код в Objective-C
  • 1
    @RocketGarden - заголовочный файл KudanCV - C ++. Вы можете написать оболочку, которая работает так же, как мой пример класса оболочки. ИЛИ вы переписываете те части вашего приложения, которые должны взаимодействовать с KudanCV в Objective-C ++ (с заголовками Objective-C). Вам не нужно переписывать те части вашего проекта, которые не связаны с KudanCV.
Показать ещё 1 комментарий
21

Вы также можете пропустить файл Objective-C. Просто добавьте файл заголовка C с исходным файлом .cpp. Имеют только C-декларации в файле заголовка и включают любой код С++ в исходный файл. Затем включите файл заголовка C в ** - Bridging-Header.h.

Следующий пример возвращает указатель на объект С++ (struct Foo), поэтому Swift может хранить в COpaquePointer вместо структуры Foo, определенной в глобальном пространстве.

Файл Foo.h(см. Swift - включен в файл моста)

#ifndef FOO_H
#define FOO_H

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

#endif

Внутри исходного файла Foo.cpp(не видно 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
    Этот ответ заслуживает способ больше upvotes. Действительно полезно.
  • 0
    Это первый раз, когда я увидел, как extern "C" оборачивает заголовок в том месте, #ifdef он включен, а не #ifdef 'ed в самом файле заголовка. Brilliant!
12

Здесь моя попытка инструмента clang для автоматизации С++/быстрой связи. Вы можете инициализировать классы С++ из swift, наследовать из класса С++ и даже переопределять виртуальные методы в swift.
Он проанализирует класс С++, который вы хотите экспортировать, и быстро сгенерируйте мост Objective-C/Objective-С++.

https://github.com/sandym/swiftpp

6

Swift напрямую не совместим с С++. Вы можете обойти проблему, обернув свой код на С++ с помощью Objective-C и используя оболочку Objective C в Swift.

4

Нет, не в одном файле.

Однако вы можете использовать С++ в Swift Projects без необходимости использования статической библиотеки или фреймворка. Как и другие пользователи, ключевым моментом является создание заголовка моста Objective-C, который # включает C-совместимые заголовки С++, которые помечены как C, совместимые с extern "C" {} трюк.

Видеоурок: https://www.youtube.com/watch?v=0x6JbiphNS4

4

У меня также есть демо-программа для быстрого объединения opencv.

Вы можете загрузить его из https://github.com/russj/swift_opencv3_demo.

Подробнее о демо http://flopalm.com/opencv-with-swift/.

2

Другие ответы немного неточны. Вы можете смешать как Swift, так и [Objective-] C [++] в одном файле, но не так, как вы ожидали.

Этот файл (c.swift) компилируется в действительный исполняемый файл с swiftc c.swift и clang -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;
}
// */
1

Я предоставляю ссылку на SE-0038 в официальном ресурсе, описанном как Это поддерживает предложения по изменениям и видимым для пользователя усовершенствованиям языка Swift.

Статус на сегодняшний день заключается в том, что это запрос функции, который был принят, но еще не запланирован.

Эта ссылка предназначена для управления всеми, кто ищет эту функцию в правильном направлении.

1

В случае, если это полезно для всех, у меня также есть краткое руководство по вызову простой статической библиотеки С++ из тривиальной утилиты командной строки Swift. Это действительно убедительное доказательство концепции кода.

Нет Objective-C, только Swift и С++. Код в библиотеке С++ вызывается оболочкой С++, которая реализует функцию с внешней связью "C". Затем эта функция ссылается на заголовок моста и вызывается из Swift.

См. http://www.swiftprogrammer.info/swift_call_cpp.html

Ещё вопросы

Сообщество Overcoder
Наверх
Меню