Example of C / C++ / Objective-C / Swift interoperability
In ViewController.swift:
hello_c("World".cString(using: String.Encoding.utf8))
In C.h:
#ifndef C_h
#define C_h
#ifdef __cplusplus
extern "C" {
#endif
void hello_c(const char * name);
#ifdef __cplusplus
}
#endif
#endif /* C_h */
In C.c:
#include "C.h"
#include <stdio.h>
void hello_c(const char * name) {
printf("Hello %s in C\n", name);
}
In Example-Bridging-Header.h:
#import "C.h"
In ViewController.swift:
CPP_Wrapper().hello_cpp_wrapped("World")
In CPP.hpp:
#pragma once
#include <string>
class CPP {
public:
void hello_cpp(const std::string& name);
};
In CPP.cpp:
#include "CPP.hpp"
#include <iostream>
using namespace std;
void CPP::hello_cpp(const std::string& name) {
cout << "Hello " << name << " in C++" << endl;
}
In CPP-Wrapper.h:
#import <Foundation/Foundation.h>
@interface CPP_Wrapper : NSObject
- (void)hello_cpp_wrapped:(NSString *)name;
@end
In CPP-Wrapper.mm:
#import "CPP-Wrapper.h"
#include "CPP.hpp"
@implementation CPP_Wrapper
- (void)hello_cpp_wrapped:(NSString *)name {
CPP cpp;
cpp.hello_cpp([name cStringUsingEncoding:NSUTF8StringEncoding]);
}
@end
In Example-Bridging-Header.h:
#import "CPP-Wrapper.h"
In ViewController.swift:
let queue = LockFreeQueue()
queue.push("1" as NSObject)
queue.push("2" as NSObject)
let first = queue.pop();
print(first as! NSString)
In lock_free_objc_wrapper.h:
#import <Foundation/Foundation.h>
#ifndef lock_free_objc_wrapper_h
#define lock_free_objc_wrapper_h
@interface LockFreeQueue : NSObject
- (void)push:(NSObject *)data;
- (NSObject *)pop;
@end
#endif
In lock_free_objc_wrapper.mm:
#import "lock_free_objc_wrapper.h"
#include "lock_free_queue.hpp"
@interface LockFreeQueue() {
lock_free_queue<void*>* queue;
}
@end
@implementation LockFreeQueue
- (instancetype)init {
if (self = [super init]) {
queue = new lock_free_queue<void*>();
}
return self;
}
- (void)dealloc {
delete queue;
}
- (void)push:(NSObject *)data {
queue->push((void*)CFBridgingRetain(data));
}
- (NSObject*)pop{
std::unique_ptr<void*> res = queue->pop();
if(res == nullptr) return nil;
return CFBridgingRelease(*res);
}
@end
In lock_free_queue.hpp:
#ifndef lock_free_queue_hpp
#define lock_free_queue_hpp
#ifdef __cplusplus
template<typename T>
class lock_free_queue {
...
public:
lock_free_queue() {
...
}
~lock_free_queue() {
...
}
std::unique_ptr<T> pop() {
...
}
void push(T new_value) {
...
}
#endif
#endif
In Example-Bridging-Header.h:
#import "lock_free_objc_wrapper.h"
In ViewController.swift:
let checker = PrimeChecker()
checker.simpleCall {
print("And back to Swift")
}
In prime_feature_objc_wrapper.h:
#import <Foundation/Foundation.h>
#ifndef prime_feature_objc_wrapper_h
#define prime_feature_objc_wrapper_h
@interface PrimeChecker : NSObject
- (void) simpleCall: (void(*)())function;
@end
#endif
In prime_feature_objc_wrapper.mm:
#import "prime_feature_objc_wrapper.h"
#include "prime_feature.hpp"
@interface PrimeChecker() {
prime_checker* checker;
}
@end
@implementation PrimeChecker
- (instancetype)init {
if (self = [super init]) {
checker = new prime_checker();
}
return self;
}
- (void)dealloc {
delete checker;
}
- (void)simpleCall: (void(*)())function {
checker->simpleCall(function);
}
@end
In prime_checker.hpp:
#ifndef prime_feature_h
#define prime_feature_h
#ifdef __cplusplus
#include <iostream>
#include <string>
class prime_checker {
public:
void simpleCall(void(*function)()){
function();
}
};
#endif
#endif
You have to pass pointer to object to closure right to C++ method and then back to Swift:
In prime_checker.hpp (void* target - raw pointer to 'self' in Swift, pass it to void(resultCallback)(bool result, void target))):
void checkIsPrime(std::string value,
void(*progressCallback)(void*),
void(*resultCallback)(bool result, void* target),
void* target) {
...
progressCallback(target);
bool x = true;
resultCallback(x, target);
...
}
In prime_feature_objc_wrapper.h:
- (void) checkIsPrime: (NSString *)value with: (void(*)(void*)) progressCallback andWith: (void(*)(bool result, void* target)) resultCallback withTarget: (void*) target ;
In prime_feature_objc_wrapper.mm:
- (void) checkIsPrime: (NSString *)value with: (void(*)(void*)) progressCallback andWith: (void(*)(bool result, void* target)) resultCallback withTarget: (void*) target{
checker->checkIsPrime([value UTF8String], progressCallback, resultCallback, target);
}
In ViewController.swift:
// raw pointer to self
let observer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
// pass pointer to c++ method
checker.checkIsPrime(self.input?.stringValue, with: { observer in
// from raw pointer to 'self'
let mySelf = Unmanaged<ViewController>.fromOpaque(observer!).takeUnretainedValue()
// update UI from main thread using mySelf
DispatchQueue.main.async{
mySelf.progress.stringValue...
}
}, andWith: { (result : Bool, observer) in
...
}, withTarget: observer)