As a Swift coder I am so confused by the apparent fragmentation in the c side of things. Somehow there is Objective-C, Objective-C++, c, and c++ and they all have there .h, .hpp, .m, .cpp, etc file extensions however I cannot find great documentation of which extension goes to which file type in XCode (although I am fairly sure for c++ it should be .hpp and .cpp).
This confusion has lead me state where I have no real idea of what I am doing when trying to expose a c++ class to my swift code. Let me explain my strategy.
I have a bridging file that was autogenerated by XCode which I have modified
Bridging-Header.h
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#include <stdio.h>
#include <stdlib.h>
int* main1() {
int *num;
num = (int *)malloc(1000 * sizeof(int));
for (int i = 0; i < 10; i++) {
num[i] = i;
}
num[10] = 10;
free(num);
return num;
}
If I am interpreting things right XCode considers this to be the header file of Objective-C code. Indeed this function is exposed to swift and works as intended.
I then created another file because if I try to import my c++ code in that file it tries to compile it like objective-c which does not go well. This file I believe would be the implementation of this header and I have been told it would be a safe place to import my c++ code.
There is also Bridging-Header.m
#ifndef Bridging_Header_h
#define Bridging_Header_h
#import "Bridging-Header.h"
#import "rectangle.hpp"
int main2() {
Rectangle* r = new Rectangle();
return 2;
}
#endif /* TryPost_Bridging_Header_h */
This code I was expecting XCode to treat like Objective-c++ code thus allowing my to safely import my c++ code additionally I thought it would be automatically linked to its corresponding header since if I tried to import it from my other file it would cause an import cycle leading to tons of issues.
However those assumptions must be wrong as this code doesnt appear to even be compiled. Swift does not see the function main2
does not show up in swift.
There is also Rectangle.hpp
#ifndef rectangle_hpp
#define rectangle_hpp
#include <stdio.h>
int main3() {
return 3;
}
class Rectangle {
int main();
};
#endif /* fancy_hpp */
I believe XCode should interpret this as C++ code. There is also
Rectangle.cpp
#include "rectangle.hpp"
int Rectangle::main() {
std::cout << "Hello world!";
return 99;
}
int main4() {
return 99;
}
Neither of these seem to be getting compiled either.
I am very confused because I don't know how to even begin dealing with imports between all of these languages nor what I should name the files if I want the compiler to automatically treat them like a certain language. How can I get my Rectangle class to be exposed to swift and maybe even print out "Hello World" when called (even though I am doubtful that printing from c++ is possible.
To be honest I dont really care about the main2
function it is just there for testing purposes and because I think I need that file to get my c++ in. If it is not included in the final project I would not mind. main1
, main2
, main4
and Rectangle
are all important however.
You cannot directly use c/c++
code in swift
because the type systems are different. Objective c/c++
is mixed meaning it understand both c/c++
types and swift
types. To consume say Rectangle c++
class, you would wrap this in a objective c/c++
class and import the objective c/c++
header in <Project>-Bridging-Header.hpp
file to expose it to Swift
.
Swift by default treats all files with extension -
*.m - as objective c files
*.mm - as objective c++ files
*.hpp - as (objective) c/c++ header files
*.cpp - as c++ files
*.c - as c files
Now coming to your example, If i understand correctly you want to use c++ class (say Rectangle
) in Swift
. Here's the layered view of the solution.
+----------------------------------+
| Rectangle (c++) |
+----------------------------------+
| RectangleWrapper (objc++) |
+----------------------------------+
| Bridging header |
+----------------------------------+
| Swift |
+----------------------------------+
// Rectangle.h
class Rectangle {
public:
void draw();
}
// Rectangle.cpp
void Rectangle::draw() {
cout << "draw rectangle" << endl;
}
// RectangleWrapper.hpp
@interface RectangleWrapper : NSObject {
@private
void* rect;
}
- (RectangleWrapper*) init;
- (void) draw;
@end
// RectangleWrapper.mm
#import "Rectangle.h"
@implementation RectangleWrapper
- (RectangleWrapper*) init {
rect = (void*)new Rectangle; // create c++ class instance
return self; // return objc++ instance
}
- (void) draw {
Rectangle* r = (Rectangle*)rect;
r->draw(); // call c++ method
}
@end
Expose your objective c++ class to swift world by simply importing the objc++ header file into Bridging-Header.hpp
.
// Bridging-Header.hpp
#import "RectangleWrapper.hpp"
Now simply use the objective c++ RectangleWrapper
class as any other swift class.
// use-rectangle.swift
let rect = RectangleWrapper()
rect.draw()
See complete code on github
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