Can I have Swift, Objective-C, C and C++ files in the same Xcode project?

24,932

YES.

You can mix Swift, C, C++, Objective-C & Objective-C++ files in the same Xcode project.

C

// 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);
}

C++

// 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;
}

Objective-C wrapper for C++

// 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

Objective-C

// 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

Objective-C++

// 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

Swift

// Declaration & definition: Swift.swift
func hello_swift(_ name: String) {
    print("Hello \(name) in Swift")
}

Bridging-Header.h

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"

Invocation from Swift

// 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")

.h (Headers)

(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.

Output

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.

Share:
24,932
SwiftArchitect
Author by

SwiftArchitect

While I enjoy a good puzzle now and then, I like to solve problems with a holistic and generalized solution†. Experiences at Apple Computer &amp; Microsoft have taught me humbling lessons in design and architecture: better pick a good algorithm than optimize a poor one, or better yet, design twice, program once. I find it very hard to write about myself, so here is a quote from an experienced resume writer: You are a successful leader and supporter of mobile software development, preemptive testing, and implementation initiatives. You have very extensive, specialized technical expertise. That would include iOS, Android and cross-platform Xamarin &amp; C# for which I have a certification (check it on LinkedIn or Xamarin University). There is a life outside StackOverflow have I been told, which I may spend with a camera and a backpack. I'm also behind SwiftArchitect blog &amp; technical discussion website. (†) A notoriously challenging example is The Returning Explorer by M. Gardner.

Updated on July 08, 2022

Comments

  • SwiftArchitect
    SwiftArchitect almost 2 years

    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?


  • dumbledad
    dumbledad over 8 years
    +1 - amazing answer, but real shame that the simple C++ method does not take a pointer or reference to another C++ object as a parameter - that's what's doing my head in.
  • MaddTheSane
    MaddTheSane over 8 years
    Note that you may need to wrap C functions in extern "C" { } if you include and call them in C++ source code. This also means you can have a function that is C compliant implemented in C++ and that is called in Swift.
  • Anchor
    Anchor over 8 years
    Awesome! Is there a performance penalty for having all these wrapper functions?
  • SwiftArchitect
    SwiftArchitect about 8 years
    Credit to the critics who have suggested edits and enhancements.
  • Dk Kumar
    Dk Kumar about 8 years
    @SwiftArchitect it's absolutely great example, but I think if you include <vector> or <iostream> in .h file of objective c++ wrapper it will is not working for me
  • user2517182
    user2517182 about 8 years
    @SwiftArchitect does this still work? #include <string> produces the following error 'string' file not found in CPP.hpp.
  • user2517182
    user2517182 about 8 years
    @SwiftArchitect I see what my problem was. I named CPP-Wrapper with .m instead of .mm You may want to change your 'Objective-C wrapper for C++' title to 'Objective-C++ wrapper for C++'. Even though you have the filename in the comments ending in .mm, if someone (like I did) creates a .m then #include <string> produces the following error 'string' file not found in CPP.hpp. Thanks for this great resource. :-)
  • SwiftArchitect
    SwiftArchitect about 8 years
    Correct. Watch out for .h, .c., .hpp, .cpp, m, .mm & .swift.
  • PashaN
    PashaN almost 7 years
    can someone provide an example how to call from .cpp to swift or objective c?