Can all 4 languages be used in the same project at all, and if so how?
There are similar questions in the flavor: Can I mix Swift with C++? Like the Objective - C .mm files to which the accepted answer is no.
Using Bridging Header
adequately, .h
that do not contain C++
statements, Objective-C
wrappers when .h
do contain C++
, .mm
files to do the actual wrapping of C++
classes, and .swift
, can the 4 languages (5 if you include Objective-C++
) build and link into a single executable?
objective-c++xcode
You can use Objective-C and Swift files together in a single project, no matter which language the project used originally. This makes creating mixed-language app and framework targets as straightforward as creating an app or framework target written in a single language.
You can work with types declared in Swift from within the Objective-C code in your project by importing an Xcode-generated header file. This file is an Objective-C header that declares the Swift interfaces in your target, and you can think of it as an umbrella header for your Swift code.
Swift is easier to read and easier to learn than Objective-C. Objective-C is over thirty years old, and that means it has a more clunky syntax. Swift streamlines code and more closely resembles readable English, similar to languages like C#, C++, JavaScript, Java, and Python.
Unlike Objective-C, which is a proper superset of C, Swift has been built as an entirely new language. Swift cannot compile C code because the syntax is not compatible.
You can mix Swift
, C
, C++
, Objective-C
& Objective-C++
files in the same Xcode project.
// Declaration: 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 */
// Definition: C.c
#include "C.h"
#include <stdio.h>
void hello_c(const char * name) {
printf("Hello %s in C\n", name);
}
// Declaration: CPP.hpp
#pragma once
#include <string>
class CPP {
public:
void hello_cpp(const std::string& name);
};
// Definition: CPP.cpp
#include "CPP.hpp"
#include <iostream>
using namespace std;
void CPP::hello_cpp(const std::string& name) {
cout << "Hello " << name << " in C++" << endl;
}
// Declaration: CPP-Wrapper.h
#import <Foundation/Foundation.h>
@interface CPP_Wrapper : NSObject
- (void)hello_cpp_wrapped:(NSString *)name;
@end
// Definition: 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
// Declaration: Objective-C.h
#import <Foundation/Foundation.h>
@interface Objective_C : NSObject
- (void)hello_objectiveC:(NSString *)name;
@end
// Definition: Objective-C.m
#import "Objective-C.h"
@implementation Objective_C
- (void)hello_objectiveC:(NSString*)name {
printf("Hello %s in Objective-C\n", [name cStringUsingEncoding:NSUTF8StringEncoding]);
}
@end
// Declaration: Objective-CPP.h
#import <Foundation/Foundation.h>
@interface Objective_CPP : NSObject
- (void)hello_objectiveCpp:(NSString *)name;
@end
// Definition: Objective-CPP.mm
#include <iostream>
#import "Objective-CPP.h"
using namespace std;
@implementation Objective_CPP
- (void)hello_objectiveCpp:(NSString *)name {
cout << "Hello " << [name cStringUsingEncoding:NSUTF8StringEncoding] << " in Objective-C++\n";
}
@end
// Declaration & definition: Swift.swift
func hello_swift(_ name: String) {
print("Hello \(name) in Swift")
}
Cannot import CPP.hpp
header file, not because of it's naming convention, but because it contains the class
keyword.
#import "C.h"
#import "CPP-Wrapper.h"
#import "Objective-C.h"
#import "Objective-CPP.h"
// Invoke C
hello_c("World".cStringUsingEncoding(NSUTF8StringEncoding))
// Can't Invoke C++ without a wrapper
// CPP().hello_cpp("World".cStringUsingEncoding(NSUTF8StringEncoding))
// Invoke C++ through Objective-C
CPP_Wrapper().hello_cpp_wrapped("World")
// Invoke Objective-C
Objective_C().hello_objectiveC("World")
// Invoke Objective-C++
Objective_CPP().hello_objectiveCpp("World")
// Invoke Swift
Swift().hello_swift("World")
(See item 3 in this Stack Overflow answer)
.h: this is the tricky part, since they are ambiguously used for all flavors of C, ++ or not, Objective or not. When a .h does not contain a single C++ keyword, like class, it can be added to the ...Bridging-Header.h, and will expose whatever function the corresponding .c or .cpp functionalities it declares. Otherwise, that header must be wrapped in either a pure C or Objective-C API.
Hello World in C
Hello World in C++
Hello World in Objective-C
Hello World in Objective-C++
Hello World in Swift
Comments
Cy-4AH:
Yes. You only need wrap C++
into C
or Objective-C
to use in Swift
.
Tommy
Indeed, I have a project that does exactly that. C++
for the thrust of the abstract cross-platform model stuff with some C
parts underneath; Objective-C
to wrap the C++
classes for Swift
purposes, Swift
to bind all that to a subclass of NSDocument
, with some custom views that interrogate the C
stuff.
MaddTheSane
Added the extern "C"
wrapper as per your excellent suggestion. To invoke the C method void hello_c(const char * name)
from C++ method hello_cpp(const std::string& name)
, add #include "C.h"
and call hello_c(name.c_str());
.
Keith Adler
The new SO-32541268: Now with parameters!
► Find this solution on GitHub and additional details on Swift Recipes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With