I’m building an iOS library that contains both Swift and C++ code.
Using the new C++ <> Swift interop from Swift 5.10, I can now skip the Objective-C bridge – which was annoying to write, and also slowed everything down in performance critical code.
I managed to set up the CocoaPod and my example project accordingly – SWIFT_OBJC_INTEROP_MODE
is set to objcxx
, and I’m using C++ 20.
Now I created CxxInstance.hpp
:
#include "MyPod-Swift.h"
enum class SomeEnum { FIRST, SECOND };
class CxxInstance {
public:
static void runIt() {
auto swiftInstance = MyPod::SwiftInstance::init();
int i = swiftInstance.getInt(); // <-- works ✅
SomeEnum e = swiftInstance.getEnum(); // <-- build error! ❌
}
};
And SwiftInstance.swift
:
public class SwiftInstance {
public init() { }
public func getInt() -> Int {
return 13
}
public func getEnum() -> SomeEnum {
return .FIRST
}
}
MyPod-Swift.h
was generated successfully and I can call MyPod::SwiftInstance::init()
.
But while getInt() -> Int
works fine and can be called from C++, getEnum() -> SomeEnum
fails to build because C++ cannot resolve that method.
In Swift it exists and I can use the enum SomeEnum
just fine – it’s just the C++ part that fails to find the getEnum()
method.
According to their Mixing Swift and C++ guide, calling Swift functions from C++, where the Swift function uses C++ types should be a supported feature, but I think they created separate “Modules” – one for C++ and one for Swift.
In my case I have a single .podspec
which includes all files – Swift and C++ – as source_files
:
Pod::Spec.new do |s|
s.name = "NitroImage"
s.version = package["version"]
s.summary = package["description"]
s.homepage = package["homepage"]
s.license = package["license"]
s.authors = package["author"]
s.platforms = { :ios => min_ios_version_supported }
s.source_files = [
# C++ part
"cpp/**/*.{hpp,cpp}",
# Implementation (Swift)
"ios/**/*.{swift}",
]
s.pod_target_xcconfig = {
# Use C++ 20
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
# Enables C++ <-> Swift interop (by default it's only C)
"SWIFT_OBJC_INTEROP_MODE" => "objcxx",
}
end
And CocoaPods always generates a default module.modulemap
:
module MyPod {
umbrella header "MyPod-umbrella.h"
export *
module * { export * }
}
I think I am using dynamically linked use_frameworks!
, if that matters.
Any ideas of how I can properly have cyclic dependencies on C++ <> Swift code within the same Pod?
1