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


131

Я просто изменил свои файлы .m на .mm и использую C ++. Есть ли способ сделать то же самое со Swift?

Ответы:


111

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

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

«Использование Swift с Cocoa и Objective-C» также говорит нам:

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


93
На самом деле, это довольно неприятно - все мы с приложениями Cocoa, включающими кодовые базы C / C ++, теперь должны поддерживать проекты, написанные на 3 языках ....
Джей

6
Я предполагаю, что Objective-c ++ - это не другой язык, а смесь c ++ и Objective-c, разница тонкая, но она все еще есть
amar

1
Как "нулевой" законный C ++? Такого нет (по крайней мере, в стандартном C ++). Приведите еще один пример
rewolf

3
Но с ObjC вы можете просто пойти .mmсвоими файлами и (почти) сделать. Не так со Swift.
чакрит

6
@rewolf, я думаю, он имеет в виду переменную с именем nil, напримерint nil
Люк

165

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


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

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

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

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

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

  1. .swift: Swift нельзя смешивать ни с чем
  2. .m: Вы можете смешать Objective-C с C . ( @Vinzzz )
  3. .mm: вы можете смешивать Objective-C с C ++ . Этот мост - Objective-C ++ . ( @Vinzzz ).
  4. .c: чистый C
  5. .cpp: вы можете смешивать C ++ и Assembly ( @Vality )
  6. .h: вездесущий и неоднозначный C , C ++ , Objective-C или Objective-C ++ , поэтому ответ зависит от того.

Ссылки


1
Исправление: в том же исходном файле .m , Objective-C является строгим надмножеством C, вы МОЖЕТЕ смешать Objective-C и C ...
Винззз

1
Нет проблем, меня даже не волнует кредит, если ответ правильный;) Кстати, .mm предназначен для смешивания Objective-C и C ++ (C и C ++ - это две разные вещи, несмотря на название )
Vinzzz

1
Я бы упомянул, что в отличие от цели C, C ++ не является надмножеством C, поэтому вы не можете смешивать C и C ++ в файле .cpp. Только C ++ и сборка.
Vality

1
На случай, если кто-то обнаружит, что этот подробный ответ не совсем помогает при попытке открыть файлы Swift в их файле Objective-C / C ++ (Xcode жалуется, что файл заголовка Swift не найден). Я обнаружил, что мне нужно импортировать «ProductName / ProductModuleName-Swift.h» в исходный файл Objective-C / C ++. Я нашел это несколько похороненным по адресу: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
AeroBuffalo 01

Хорошая точка зрения. Для рабочего проекта, сочетающего эти языки, посмотрите stackoverflow.com/a/32546879/218152 .
SwiftArchitect 01

72

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

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

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

Ключ в том, чтобы создать общий заголовок Project-Bridging-Header.h и поместить туда заголовки Objective C.

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


Спасибо за это Джиану!
Джейсон Элвуд

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

@API: Нет, вы упускаете суть. ObjCtoCPlusPlus.h/ ".mm" существует с единственной целью - предоставить интерфейс Ob-C для кода C ++ - это мост, который здесь является необходимым компонентом. Оставьте включения там, где они есть, и добавьте метод в ObjCtoCPlusPlus.…файлы для каждого метода C ++, к которому вам нужен доступ. Вам следует прочитать на sourcemaking.com/design_patterns/adapter
Слипп Д. Томпсон

Я загрузил ваш пример, и он отлично подходит для СТАТИЧЕСКОЙ функции, которую класс предлагает в качестве примера, но мне не удается адаптировать пример для дополнительной нестатической функции, которая будет использоваться извне ... Возможно ли это? (Я делал домашнее задание по C ++ несколько десятилетий назад ... Я сейчас не самый острый карандаш из коробки)
Исаак

31

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

В следующем примере возвращается указатель на объект C ++ (struct Foo), поэтому Swift может хранить его в COpaquePointer вместо того, чтобы struct 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's 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. Действительно полезно.
rsp1984

Это первый раз, когда я вижу, extern "C"что заголовок оборачивается в том месте, где он включен, а не #ifdefв самом файле заголовка. Brilliant!
dcow

27

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

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


Я думаю, это решает проблему, с которой я столкнулся сегодня, пытаясь использовать стороннюю библиотеку KudanCV со Swift. Мой заголовок моста импортирует их .h-файл, который содержит импорт в <memory> <strings> и <vectors>, которые, как я полагаю, из библиотек или файлов C ++, в результате мой код Swift не будет компилироваться. Я был бы признателен, если бы кто-нибудь мог сказать мне, есть ли способ обойти это ... или если мне придется переписать весь свой код в Objective-C
Rocket Garden

1
@RocketGarden - заголовочный файл KudanCV - это C ++. Вы можете написать оболочку, которая работает так же, как мой пример класса оболочки. ИЛИ вы переписываете те части вашего приложения, которые должны взаимодействовать с KudanCV, на Objective-C ++ (с заголовками Objective-C). Вам не нужно переписывать те части вашего проекта, которые не связаны с KudanCV.
литейный

Спасибо за это, я понял это примерно через 5 минут, но полезно записать это для других.
Rocket Garden

13

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

https://github.com/sandym/swiftpp


8

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


Это то, что я сделал. Я написал статью о том, как интегрировать C ++ в быстрый проект: Learningswift.brightdigit.com/integrating-c-plus-plus-swift
leogdion


4

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

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

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


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;
}
// */

Ваш пример кода написан на C, а не на C ++. Лучше пойти с примером <iostream> ИМХО.
kakyo

2

Одна уловка (из многих) заключается в том, что

Вам нужен отдельный заголовок для вашего связующего файла obj-c ++ ...

Вы не можете просто поместить @interface и @implementation в один и тот же файл .mm, как это часто бывает обычно.

Итак, в вашем файле заголовка моста у вас есть

#import "Linkage.hpp"

Linkage.hpp имеет @interface для Linkage, а Linkage.mm имеет @implementation для .mm

А потом

... на самом деле вы не #include "yourCpp.hpp" в Linkage.hpp.

Вы вставляете только #include "yourCpp.hpp"файл Linkage.mm, а не файл Linkage.hpp.

Во многих онлайн-примерах / учебниках автор просто помещает @interface и @implementation в один и тот же файл .mm, как это часто бывает.

Это будет работать в очень простых примерах моста cpp, но,

Проблема в:

если ваш yourCpp.hpp имеет какие-либо функции C ++, которые обязательно будут (например, первая строка #include <something>), то процесс завершится ошибкой.

Но если вы просто не имеют #include "yourCpp.hpp"в Linkage заголовка файла (это нормально , чтобы иметь его в файле .mm, очевидно , вам нужно) - это работает.

Опять же, это, к сожалению, только один совет во всем процессе.


1

Если это кому-то будет полезно, у меня также есть краткое руководство по вызову простой статической библиотеки C ++ из простой утилиты командной строки Swift. Это действительно простое доказательство концептуального фрагмента кода.

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

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


1

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.