Interoperability

48.1 Objective-C

Mixed projects use a bridging header (Objective-C → Swift) and an auto-generated ModuleName-Swift.h header (Swift → Objective-C).

Annotate Objective-C headers for better Swift imports: NS_SWIFT_NAME, nullable/nonnull, NS_REFINED_FOR_SWIFT, NS_SWIFT_UI_ACTOR, NS_SWIFT_SENDABLE, generics (NSArray<NSString *>).

Bridged types: String ↔ NSString, Array ↔ NSArray, Dictionary ↔ NSDictionary, Data ↔ NSData, Error ↔ NSError, completion handlers → async.

import Foundation

@objc protocol LegacyDelegate { func didFinish(_ result: String) }

@objcMembers                                  // expose all members to Objective-C
class Bridge: NSObject {
    dynamic var progress: Double = 0          // KVO-compatible (dynamic dispatch)
    func start() {}
    @objc(startWithName:) func start(name: String) {}
}

let selector = #selector(Bridge.start)
let keyPath = #keyPath(Bridge.progress)

48.2 C Interop

Expose Swift to C with @_cdecl("swift_add") (or the official @c attribute in newer Swift).

// C libraries are imported via module maps (or system libraries); C functions are callable directly
import Darwin                                 // Glibc on Linux, ucrt on Windows
let length = strlen("hello")
var buffer = [CChar](repeating: 0, count: 256)
gethostname(&buffer, buffer.count)
let hostname = String(cString: buffer)

// Passing a Swift closure as a C callback (no captures allowed: use a context pointer)
let compare: @convention(c) (UnsafeRawPointer?, UnsafeRawPointer?) -> Int32 = { a, b in
    let x = a!.load(as: Int32.self), y = b!.load(as: Int32.self)
    return x < y ? -1 : (x > y ? 1 : 0)
}
var values: [Int32] = [5, 2, 9]
qsort(&values, values.count, MemoryLayout<Int32>.stride, compare)
// module.modulemap for a C library target in SwiftPM
module CMathLib {
    header "mathlib.h"
    link "mathlib"
    export *
}

48.3 C++ Interop (Swift 5.9+)

Supports C++ classes, templates (instantiated specializations), std::string, std::vector, std::map, std::optional, and calling Swift from C++ via generated headers. Used for incremental adoption in large C++ codebases. Check the Swift C++ interop documentation for supported features.

// Enable in Package.swift: swiftSettings: [.interoperabilityMode(.Cxx)]
import CxxStdlib
import MyCxxLib

var vec = std.vector<CInt>()
vec.push_back(42)
let s = std.string("hello from C++")
print(String(s))

var calc = MyCxxLib.Calculator()              // C++ classes imported as Swift structs/classes
print(calc.add(2, 3))

48.4 Other Interop

Java/Android: the swift-java project (JNI interop). JavaScript: JavaScriptKit (with Swift Wasm). Python: PythonKit. Rust: via C ABIs (swift-bridge).