Swift 5.9's C++ interoperability transforms how developers leverage mature C++ libraries from Swift's expressive, safe environment. Through a practical ATM implementation, we explore calling C++ functions, wrapping classes, and sharing data types across languages—complete with build configurations for SwiftPM and Xcode. This breakthrough enables truly shared codebases across Apple platforms, Linux, and embedded systems.
The chasm between Swift's modern safety and C++'s raw performance has long been a barrier for Apple platform developers. With Swift 5.9's stabilized C++ interoperability, that gap collapses—letting engineers harness decades of battle-tested C++ libraries without sacrificing Swift's expressiveness. Through a hands-on ATM implementation, we'll dissect this transformative capability.
The Cross-Language Blueprint
At the project's core lies a deliberate separation:
├── ATMProj (SwiftUI app)
│ ├── View Models
│ ├── UI Components
└── cpp (C++ core)
├── CMakeLists.txt
├── Package.swift
└── Sources
├── C++ ATM logic
└── Swift wrappers
The cpp directory houses the financial logic as a CMake-built static library, while SwiftPM orchestrates integration via a unified manifest. This structure ensures iOS/macOS apps and CLI tools share identical business logic.
C++ Core: Performance-Critical Foundations
The ATM's logic exemplifies clean C++ encapsulation:
// ATM.h
#pragma once
class ATM {
public:
ATM(int initialBalance);
bool withdraw(int amount);
int getBalance() const;
private:
int balance;
};
// ATM.cpp
#include "ATM.h"
bool ATM::withdraw(int amount) {
if (balance >= amount) {
balance -= amount;
return true;
}
return false;
}
CMake builds this into a static library, while ATMWithdrawCpp.h re-exposes headers for Swift consumption. The critical build configuration enforces C++17:
target_include_directories(ATMWithdrawCpp PUBLIC ${HEADER_PATH})
set_target_properties(ATMWithdrawCpp PROPERTIES CXX_STANDARD 17)
Swift Integration: Bridging with Safety
The magic unfolds in Swift's interoperability layer. Notice how ATMWrapper creates a Swifty interface for the C++ class:
import ATMWithdrawCpp
public struct ATMWrapper {
private var underlying: ATM // Direct C++ instance
public init(initialBalance: Int32) {
underlying = ATM(initialBalance)
}
public mutating func withdraw(amount: Int32) -> Bool {
return underlying.withdraw(amount)
}
}
SwiftPM's manifest is configured for cross-language harmony:
// Package.swift
targets: [
.target(
name: "ATMWithdrawCpp",
publicHeadersPath: "include"
),
.target(
name: "ATMPackage",
dependencies: ["ATMWithdrawCpp"],
swiftSettings: [.interoperabilityMode(.Cxx)]
)
]
The .interoperabilityMode(.Cxx) flag is non-negotiable—it activates Swift's C++ bridging capabilities.
From CLI to SwiftUI: Shared Logic in Action
The same ATMWrapper powers both a terminal interface:
// CLI
var atm = ATMWrapper(initialBalance: 1000)
if atm.withdraw(amount: amount) {
print("✅ Withdrawn \(amount)")
}
And a reactive SwiftUI application:
// ViewModel
class ATMViewModel: ObservableObject {
@Published var balance: Int32
private var atm: ATMWrapper
func withdraw(amount: String) {
guard let value = Int32(amount),
atm.withdraw(amount: value) else { return }
balance = atm.getBalance()
}
}
// SwiftUI View
Button("Withdraw") {
viewModel.withdraw(amount: input)
}
Xcode integration requires one critical build setting: -cxx-interoperability-mode=default under "Other Swift Flags".
The New Frontier: Write Once, Run Anywhere
This interoperability transcends Apple's ecosystem. The C++ ATM core compiles anywhere—Linux, Windows, embedded systems—while Swift wrappers adapt it to local conventions. SwiftPM and CMake automate cross-platform builds, eliminating logic duplication. As Swift's C++ support matures, it threatens the raison d'être of many cross-platform frameworks by enabling true native development with shared C++ underpinnings.
Developers now face a compelling choice: rewrite performance-critical C++ in Swift, or seamlessly integrate existing libraries while writing modern UI layers. For resource-intensive applications, the latter may prove irresistible.
Source: Artur Gruchała, Swift and C++ Interoperability in Practice

Comments
Please log in or register to join the discussion