
If you need to call C++ from Swift on iOS or tvOS, you no longer have to write an Objective-C++ bridge. As of 2026, with Xcode 15 and later, Swift talks to C++ directly through its built-in C++ interoperability mode. You expose your C++ header with a module map, flip one build setting, import the module into Swift, and call your class as if it were native. This post walks through a minimal working example that runs on both iOS and tvOS.
A long time ago, I was asked to write C++ that both Android and iOS would call. It was mostly for security, and I am not going to describe that routine here.
The language of the app is still Swift, and you rarely need C++ to build one. There are some fields where writing certain parts in a low-level language gives you an extra layer of security, so in those cases it can be worth the trouble. For everything else, stay in Swift.
When would you actually use C++ in a Swift app?
Using C++ in an iOS or tvOS project is a deliberate choice. The cases where I have seen it pay off are narrow but real:
- Shared cross-platform logic. If you already maintain a C++ core that ships on Android through the NDK, reusing the same code on iOS keeps a single source of truth instead of two implementations that drift apart. That was my situation: one security-sensitive routine, two platforms.
- Security-sensitive routines. Keeping certain logic in a compiled, lower-level language raises the effort required to inspect or tamper with it. It is not magic, but it is one more layer.
- Performance-critical paths. Existing C++ for signal processing, cryptography, or heavy math is often faster to reuse than to rewrite in Swift.
If none of those apply, write Swift. The interop is genuinely nice now, but it is still a maintenance cost you only want to take on for a reason.
This article wires up a small C++ example. It does not teach C++. The demo files are basic on purpose:
//
// MyCppClass.hpp
// cppexample
//
// Created by davthecoder on 16/09/2025.
//
#pragma once
#include <string>
class MyCppClass {
public:
MyCppClass(int val);
std::string greet() const;
private:
int value;
};
//
// MyCppClass.cpp
// cppexample
//
// Created by davthecoder on 16/09/2025.
//
#include "MyCppClass.hpp"
MyCppClass::MyCppClass(int val) : value(val) {}
std::string MyCppClass::greet() const {
return "Hello from C++, value is " + std::to_string(value);
}
//
// module.modulemap
// cppexample
//
// Created by davthecoder on 16/09/2025.
//
module MyCppModule {
header "MyCppClass.hpp"
export *
}
//
// cppexample-Bridging-Header.h
// cppexample
//
// Created by davthecoder on 16/09/2025.
// Keep it empty
The files sit in the project like this:

What is the module map doing here?
The module map is the piece that makes the no-bridge approach work. In the older world you would write an Objective-C++ (.mm) wrapper, expose a plain Objective-C interface, and let Swift talk to that. The wrapper was pure boilerplate, and every new C++ type meant more of it.
The module map replaces all of that. It declares a Clang module named MyCppModule that exposes MyCppClass.hpp, and export * re-exports everything the header pulls in. Once Swift’s C++ interoperability is turned on, import MyCppModule gives you the C++ class directly, constructors, methods, and all, with no hand-written glue in between.
The bridging header in the demo is kept empty on purpose. I include it so the project layout matches a standard Xcode setup, but the actual C++ visibility comes from the module map, not the bridging header.
How to call C++ from Swift in Xcode
Once the .hpp, .cpp, and .modulemap files are in the project:
- Add your C++ source and header (
MyCppClass.cppandMyCppClass.hpp) plus themodule.modulemapfile to your Xcode target so they compile with the app. - Open Build Settings, find Swift Compiler - Language, and set C++ and Objective-C interoperability to C++ / Objective-C++. This is the switch that turns on direct C++ interop for the whole target.
- Make sure the module map is discoverable, for example by pointing the Swift compiler’s import search path at the folder that contains
module.modulemap, soimport MyCppModuleresolves. - In your Swift file, add
import MyCppModulealongside your usual imports. - Construct the C++ object and call its methods as if they were Swift:
let cppObj = MyCppClass(42)and thencppObj.greet(). - Build and run on an iOS or tvOS simulator (or device) and confirm the value returned from C++ shows up in your UI.
Nothing else works until this build setting is on:

Then call the C++ from Swift. This demo uses the Content View Xcode generates for a new project:
//
// ContentView.swift
// cppexample
//
// Created by davthecoder on 16/09/2025.
//
import SwiftUI
import MyCppModule // <-- Import the C++ module
struct ContentView: View {
var body: some View {
VStack {
let cppObj = MyCppClass(42) // < --Create an instance of the C++ class
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("\(cppObj.greet())") // <-- cppObj.greet() Call a method from the C++ class
.padding()
}
.padding()
}
}
#Preview {
ContentView()
}
greet() returns a C++ std::string, and I interpolate it straight into a SwiftUI Text. The interop layer bridges the C++ string into something Swift can print, so there is no manual conversion in this simple case. Not every C++ type maps this cleanly, though. Templates, raw pointers, and ownership-heavy APIs can need extra care or a thin C++ shim with a friendlier surface, so keep the interface you expose to Swift as narrow and value-oriented as you can.
Does this work the same way on tvOS?
Yes. That is the part I like most about this approach. The interop is a compiler feature, not a platform-specific SDK, so the same C++ files, the same module map, and the same build setting carry over to a tvOS target unchanged. You write one integration and point two targets at it.
The same project runs on both simulators:

Happy coding.
David Cruz davthecoder.com

Si necesitas llamar a C++ desde Swift en iOS o tvOS, ya no tienes que escribir un puente en Objective-C++. A fecha de 2026, con Xcode 15 y posteriores, Swift habla con C++ directamente mediante su modo integrado de interoperabilidad con C++. Expones la cabecera de C++ con un mapa de módulos, activas un único ajuste de compilación, importas el módulo en Swift y llamas a tu clase como si fuera nativa. Este artículo recorre un ejemplo mínimo que funciona, y que corre tanto en iOS como en tvOS.
Hace mucho tiempo me pidieron que escribiera C++ al que llamaran tanto Android como iOS. Era sobre todo por seguridad, y no voy a describir esa rutina aquí.
El lenguaje de la app sigue siendo Swift, y rara vez necesitas C++ para construir una. Hay campos en los que escribir ciertas partes en un lenguaje de bajo nivel te da una capa extra de seguridad, y en esos casos el lío puede merecer la pena. Para todo lo demás, quédate en Swift.
¿Cuándo usarías de verdad C++ en una app de Swift?
Usar C++ en un proyecto de iOS o tvOS es una decisión deliberada. Los casos en los que lo he visto compensar son estrechos, pero reales:
- Lógica compartida entre plataformas. Si ya mantienes un núcleo en C++ que se distribuye en Android a través del NDK, reutilizar el mismo código en iOS conserva una única fuente de verdad, en vez de dos implementaciones que se separan. Esa era mi situación: una rutina sensible a la seguridad, dos plataformas.
- Rutinas sensibles a la seguridad. Mantener cierta lógica en un lenguaje compilado y de más bajo nivel sube el esfuerzo necesario para inspeccionarla o manipularla. No es magia, pero es una capa más.
- Caminos críticos de rendimiento. Un C++ ya existente, para procesamiento de señal, criptografía o matemáticas pesadas, suele ser más rápido de reutilizar que de reescribir en Swift.
Si nada de eso encaja, escribe Swift. La interoperabilidad ahora es de verdad agradable, pero sigue siendo un coste de mantenimiento que solo quieres asumir con un motivo.
Este artículo enchufa un ejemplo pequeño de C++. No enseña C++. Los ficheros de la demo son básicos a propósito:
//
// MyCppClass.hpp
// cppexample
//
// Created by davthecoder on 16/09/2025.
//
#pragma once
#include <string>
class MyCppClass {
public:
MyCppClass(int val);
std::string greet() const;
private:
int value;
};
//
// MyCppClass.cpp
// cppexample
//
// Created by davthecoder on 16/09/2025.
//
#include "MyCppClass.hpp"
MyCppClass::MyCppClass(int val) : value(val) {}
std::string MyCppClass::greet() const {
return "Hello from C++, value is " + std::to_string(value);
}
//
// module.modulemap
// cppexample
//
// Created by davthecoder on 16/09/2025.
//
module MyCppModule {
header "MyCppClass.hpp"
export *
}
//
// cppexample-Bridging-Header.h
// cppexample
//
// Created by davthecoder on 16/09/2025.
// Keep it empty
Los ficheros quedan en el proyecto así:

¿Qué está haciendo aquí el mapa de módulos?
El mapa de módulos es la pieza que hace funcionar el enfoque sin puente. En el mundo de antes escribías un wrapper en Objective-C++ (.mm), exponías una interfaz lisa de Objective-C y dejabas que Swift hablara con eso. El wrapper era puro texto de relleno, y cada tipo nuevo de C++ significaba más de lo mismo.
El mapa de módulos sustituye todo eso. Declara un módulo de Clang llamado MyCppModule que expone MyCppClass.hpp, y export * reexporta todo lo que la cabecera arrastra. Cuando la interoperabilidad de Swift con C++ está activada, import MyCppModule te da la clase de C++ directamente, constructores, métodos y todo, sin pegamento escrito a mano por el medio.
La cabecera de puente de la demo se deja vacía a propósito. La incluyo para que la disposición del proyecto coincida con un montaje estándar de Xcode, pero la visibilidad real de C++ sale del mapa de módulos, no de la cabecera de puente.
Cómo llamar a C++ desde Swift en Xcode
Cuando los ficheros .hpp, .cpp y .modulemap ya están en el proyecto:
- Añade tu fuente y tu cabecera de C++ (
MyCppClass.cppyMyCppClass.hpp) más el ficheromodule.modulemapal target de Xcode, para que compilen con la app. - Abre Build Settings, busca Swift Compiler - Language y pon C++ and Objective-C interoperability en C++ / Objective-C++. Este es el interruptor que activa la interoperabilidad directa con C++ para todo el target.
- Asegúrate de que el mapa de módulos se pueda descubrir, por ejemplo apuntando la ruta de búsqueda de imports del compilador de Swift a la carpeta que contiene
module.modulemap, de modo queimport MyCppModuleresuelva. - En tu fichero de Swift, añade
import MyCppModulejunto a tus imports de siempre. - Construye el objeto de C++ y llama a sus métodos como si fueran de Swift:
let cppObj = MyCppClass(42)y despuéscppObj.greet(). - Compila y ejecuta en un simulador de iOS o tvOS (o en un dispositivo) y confirma que el valor devuelto desde C++ aparece en tu interfaz.
Nada más funciona hasta que este ajuste de compilación está activado:

Después llama al C++ desde Swift. Esta demo usa la Content View que genera Xcode para un proyecto nuevo:
//
// ContentView.swift
// cppexample
//
// Created by davthecoder on 16/09/2025.
//
import SwiftUI
import MyCppModule // <-- Import the C++ module
struct ContentView: View {
var body: some View {
VStack {
let cppObj = MyCppClass(42) // < --Create an instance of the C++ class
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("\(cppObj.greet())") // <-- cppObj.greet() Call a method from the C++ class
.padding()
}
.padding()
}
}
#Preview {
ContentView()
}
greet() devuelve un std::string de C++, y yo lo interpolo directamente en un Text de SwiftUI. La capa de interoperabilidad convierte la cadena de C++ en algo que Swift puede imprimir, así que en este caso sencillo no hay conversión manual. Eso sí: no todos los tipos de C++ encajan con esta limpieza. Las plantillas, los punteros crudos y las APIs cargadas de propiedad pueden necesitar cuidado extra, o una lámina fina de C++ con una superficie más amable, así que mantén la interfaz que expones a Swift tan estrecha y orientada a valores como puedas.
¿Esto funciona igual en tvOS?
Sí. Es la parte que más me gusta de este enfoque. La interoperabilidad es una función del compilador, no un SDK específico de una plataforma, así que los mismos ficheros de C++, el mismo mapa de módulos y el mismo ajuste de compilación pasan a un target de tvOS sin cambios. Escribes una integración y apuntas dos targets hacia ella.
El mismo proyecto corre en los dos simuladores:

¡A programar!
David Cruz davthecoder.com
Loading comments…Cargando comentarios…