Can I mix Swift with C++? Like the Objective-C .mm files
No. When you switch from .m to .mm you are actually switching from Objective-C to a different language (which has many subtle differences) called Objective-C++. So you're not really using C++; you're using Objective-C++ which accepts most C++ as input (in the same way that C++ accepts most but not all C as input). When I say it's not quite C++, consider a C++ file that includes a variable named nil
(which is legal C++) and then try to compile that as Objective-C++.
Swift doesn't have the same relationship. It is not a superset of C or C++, and you can't directly use either in a .swift
file.
"Using Swift with Cocoa and Objective-C" also tells us:
You cannot import C++ code directly into Swift. Instead, create an Objective-C or C wrapper for C++ code.
I wrote a simple Xcode 6 project that show how to mix C++, Objective C and Swift code:
https://github.com/romitagl/shared/tree/master/C-ObjC-Swift/Performance_Console
In particular the example call an Objective C and a C++ function from the Swift.
The key is to create a shared header Project-Bridging-Header.h and put the Objective C headers there.
Please download the project as a complete example.
The confusion may come from the assumption that merely changing a file extension from .m
to .mm
is all you need to bridge the languages, when, in reality, it does nothing of that sort. It is not the .mm
that causes friction with .cpp
, it is the .h
header which must positively not be a C++
header.
Same project: Yes.
In the same project, you can happily mix C, C++, Objective-C, Objective C++, Swift, and even Assembly.
...Bridging-Header.h
: you expose C, Objective-C and Objective-C++ to Swift using this bridge<ProductModuleName>-Swift.h
: exposes automatically your Swift classes marked with@objc
to Objective-C.h
: this is the tricky part, since they are ambiguously used for all flavors of C, ++ or not, Objective or not. When a.h
does not contain a single C++ keyword, likeclass
, it can be added to the...Bridging-Header.h
, and will expose whatever function the corresponding.c
or.cpp
functionalities it declares. Otherwise, that header must be wrapped in either a pure C or Objective-C API.
Same file: No.
In the same file, you can't mix all 5. In the same source file:
.swift
: you can't mix Swift with anything.m
: you can mix Objective-C with C. (@Vinzzz).mm
: you can mix Objective-C with C++. This bridge is Objective-C++. (@Vinzzz)..c
: pure C.cpp
: you can mix C++ & Assembly (@Vality).h
: ubiquitous and ambiguous C, C++, Objective-C or Objective-C++, so the answer is it depends.
References
- Invoke Assembly from C++ (Brett Hale)
- Invoke Swift from Objective-C (Svitlana)
- Invoke C, C++, Obj-C, Obj-C++ from Swift (SwiftArchitect, self)
- To download a full iOS 9, Xcode 7 project, search for SO-32541268 in Swift Recipes.
You can also skip the Objective-C file in between. Just add a C header file with a .cpp source file. Have only C declarations in the header file and include any C++ code in the source file. Then include the C header file in the **-Bridging-Header.h.
The following example returns a pointer to a C++ object (struct Foo) so Swift can store in a COpaquePointer instead of having struct Foo defined in the global space.
Foo.h file (seen by Swift - included in the bridging file)
#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
Inside source file Foo.cpp (not seen by 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;
}