You can use Objective-C and Swift files together in a single project, no matter which language the project used originally. This makes creating mixed-language app and framework targets as straightforward as creating an app or framework target written in a single language.
To access and use swift classes or libraries in objective-c files start with an objective-c project that already contains some files. Add a new Swift file to the project. In the menu select File>New>File… then select Swift File, instead of Cocoa Touch Class. Name the file and hit create.
Swift cannot compile C code because the syntax is not compatible. Swift can interoperate wit C code (see Interacting with C APIs article for more information). However, C code behind the APIs needs to be compiled separately, using a C compiler.
Add any Objective-C file to your Swift project by choosing File -> New -> New File -> Objective-C File. Upon saving, Xcode will ask if you want to add a bridging header. Choose 'Yes'.
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.
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, like class
, 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.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
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.
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;
}
I have just made a little example project using Swift, Objective-C and C++. It's a demo of how to use OpenCV stitching in iOS. The OpenCV API is C++ so we can't talk to it directly from Swift. I use a small wrapper class who's implementation file is Objective-C++. The Header file is clean Objective-C, so Swift can talk to this directly. You have to take care not to indirectly import any C++-ish files into the the headers that Swift interacts with.
The project is here: https://github.com/foundry/OpenCVSwiftStitch
Here's my attempt at a clang tool to automate C++/swift communication. You can instanciate C++ classes from swift, inherit from C++ class and even override virtual methods in swift.
It will parse the C++ class you want to export to swift and generate the Objective-C/Objective-C++ bridge automatically.
https://github.com/sandym/swiftpp
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With