Mobile
Article

Using C and C++ in an iOS App with Objective-C++

By Rico Zuñiga

In my previous tutorial, I discussed how to develop Android apps in C or C++ using the Native Development Kit. In this tutorial, I’ll introduce how to use C or C++ together with Objective-C in iOS. Unlike Android which needs a special API (the NDK) to support native development, iOS supports it by default. C or C++ development is more straightforward with iOS because of a feature called ‘Objective-C++’. I’ll discuss what Objective-C++ is, its limitations and how it’s used for building iOS apps.

What Is Objective-C++?

Objective-C++ may sound like a new programming language, but it’s not. It’s a combination of two languages, Objective-C and C++. Apple provides Objective-C++ as a convenient mechanism for mixing Objective-C code with C++ code.

Objective-C is close to C but with object-oriented features implemented as a thin layer on top of C. It’s a strict superset of C which makes any C code a valid Objective-C program.

Even though Swift is now the recommended language for developing iOS apps, there are still good reasons to use older languages like C, C++ and Objective-C. Despite the quick rise of Swift, Objective-C is still the dominant language on iOS because of the sheer number of existing apps and libraries already created with it.

One reason to use Objective-C is to port an existing C/C++ program written for another platform to iOS. Developing cross-platform apps using C or C++ is possible with some careful planning. Despite Swift being open source, it’s not yet fully supported other platforms. Another use case is the ability to leverage existing native code libraries that are already available. This is one of the most important reasons to still use C/C++/Objective-C for iOS apps.

Using Objective-C++

The final project for this tutorial can be found on GitHub.

Create the Project

Open Xcode and choose Create a new Xcode project.

Welcome Screen

In the template selection screen, choose Single View Application from the iOS Application tab and click Next.

Choose Template

In the project options screen, name the product HelloCpp. Enter your organization and organization identifier in reverse domain name style.

Project Options

Because it’s not really a language, there’s no option to create an Objective-C++ project. What’s available is either Objective-C or Swift. For this project, choose Objective-C. Leave the other options as they are and click Next and choose a folder to save the project.

Create Project

C++

Time to add some C++ code. If this is your first time with C++, check out this tutorial on the language. Look at the Project Navigator pane on the left. Most of the files end with either an .h or .m. Those that end with .h are header files while those with .m are Objective-C source files.

Create a C++ class that will be called from an Objective-C file. Create a new file using the File -> New -> File… menu item or press ⌘ + N. In the file template window that appears, select iOS -> Source -> C++ File and click Next.

File Template

Name the file Greeting, keep the Also create a header file box checked and click Next. Save the file inside the HelloCpp folder.

File Options

The project’s structure should now look like the following. Feel free to drag files around to improve the arrangement in the Project Navigator.

HelloCpp Greeting

Open Greeting.hpp and add the following code between the include <stdio.h> and #endif /* Greeting_hpp */ lines:

#include <string>

class Greeting {
    std::string greeting;
public:
    Greeting();
    std::string greet();
};

Define these methods in Greeting.cpp by adding the following code after the include "Greeting.hpp" line:

Greeting::Greeting() {
    greeting = "Hello C++!";
}

std::string Greeting::greet() {
    return greeting;
}

This is simple code that creates a class named Greeting with a single method named greet() that returns a string value.

Objective-C with C++

Now that you’ve added the simple C++ Greeting class, try calling this from Objective-C. Open ViewController.m and import the Greeting.hpp header file:

#import "ViewController.h"
#import "Greeting.hpp"
...

Declare a variable of type Greeting inside the ViewController’s @interface block.

@interface ViewController ()
{
    Greeting greeting;
}
@end

Show live issues

If the Show live issues option is enabled, an error saying Unknown type name ‘Greeting’ will instantly appear after adding the previous line of code. To fix this issue, rename ViewController.m to ViewController.mm. This simple naming convention tells Xcode that ViewController wants to mix Objective-C with C++. After renaming the file, the error should disappear.

Rename ViewController

Let’s make the app more interactive by adding a button. Select Main.storyboard from the Project Navigator to show the View Controller scene. Drag a button from the Object Library to the center of the view as shown below. Change the text to Tap Me!.

Add Button

Create a UIButton outlet that points to the recently created button. While still in the Main.storyboard screen, open the Assistant Editor by toggling it from the toolbar. Press the control key on the keyboard and drag a connector from the button to a line below the greeting variable. Name this outlet helloButton.

Hello Button

Open ViewController.h and add the following IBAction method between @interface and @end:

- (IBAction)showGreeting;

Define this method in ViewController.mm with the following code inserted after the - (void)didReceiveMemoryWarning function and before @end:

- (IBAction)showGreeting {

    NSString* newTitle = [NSString stringWithCString:greeting.greet().c_str() encoding:[NSString defaultCStringEncoding]];

    [helloButton setTitle:newTitle forState:UIControlStateNormal];
}

This method calls the greet() method defined in the C++ class Greeting and uses the string value it returns to replace the Tap Me! button’s title. Connect the button to this action using the same control + drag technique. Go back to the Main.storyboard screen and open the Assistant Editor via the toolbar then control + drag a connector from the button to the - (IBAction)showGreeting method’s body. The small hollow circle on the left of the - (IBAction)showGreeting method should be activated/filled indicating that the Tap Me! button is now connected to that action.

Show Greeting

Build and run the app. Notice that the button appears off-center on the simulator. Fix this by enabling Auto Layout constraints using the Control + drag technique. Connect the button to its container and enable both vertical and horizontal centering. Run the app again to see the improvements.

Center Button

Limitations

Objective-C++ doesn’t actually merge Objective-C with C++ features. Meaning, Objective-C classes won’t have features that are available to C++ and vice versa. The following code examples illustrate these limitations:

Calling a C++ Object Using Objective-C Syntax Will Not Work

std::string greet = [greeting greet]; // error

Constructors or Destructors Cannot Be Added to an Objective-C Object

@interface ViewController ()
{
    Greeting greeting;
    IBOutlet UIButton *helloButton;
    ViewController(); // error
    ~ViewController(); // error
}
@end

The keywords this and self Cannot Be Used Interchangeably

std::string greet = self->greeting.greet(); // works
std::string greet2 = this->greeting.greet(); // error

A C++ Class Cannot Inherit from an Objective-C Class

#include <stdio.h>
#include <string>
#include "ViewController.h"

class Greeting: public ViewController { // error
    std::string greeting;
public:
    Greeting();
    std::string greet();
};

An Objective-C Class Cannot Inherit from a C++ Class

#import "Greeting.hpp"

@interface Goodbye : Greeting // error

@end

Exception Handling Is Also Not Fully Supported When Mixing Objective-C and C++

An exception thrown in Objective-C code cannot be caught in C++ code while an exception thrown in C++ code cannot be caught in Objective-C code.

double divide(int dividend, int divisor) {
    if ( divisor == 0 ) {
        throw "Cannot divide by zero!"; // will not be caught in Objective-C
    }

    return (dividend/divisor);
}

Reusing Libraries

The ability to reuse existing C/C++ libraries is one of the most important use cases in considering native languages and it’s a straightforward process in iOS. While Android still requires a separate NDK, iOS already supports C and C++.

SDL

As with the Android NDK tutorial, we’ll use SDL in this example. The Simple DirectMedia Layer is an open source hardware abstraction library used primarily for games or anything that involves high-performance graphics. It’s written in C so can be easily included in Objective-C code.

Project Setup

First download the SDL source from the download page or clone the Mercurial repo with:

hg clone http://hg.libsdl.org/SDL

After the download or clone has finished, create a new Single View Application project in Xcode. Name it HelloSDL with the language set to Objective-C.

You’ll be starting from scratch so in the Project Navigator, select the following highlighted files and move them to the trash:

Delete Files

Remove the following keys from the Info.plist file.

Remove Keys

Add the SDL Library project to HelloSDL using the File -> Add Files to Hello SDL menu item. Navigate to the downloaded or cloned SDL folder, into Xcode-iOS/SDL/ and then choose SDL.xcodeproj.

Select the main HelloSDL project in the Project Navigator and under the Targets, select HelloSDL. Scroll down to the Linked Frameworks and Libraries section.

Linked Frameworks and Libraries

Click the + button to manually add libSDL2.a and the following frameworks:

  • AudioToolbox.framework
  • CoreAudio.framework
  • CoreGraphics.framework
  • CoreMotion.framework
  • Foundation.framework
  • GameController.framework
  • OpenGLES.framework
  • QuartzCore.framework
  • UIKit.framework

Add libSDL2.a

Use Command+Click to multi select the frameworks. Tidy up the Project Navigator by selecting the newly added frameworks and grouping them using the New Group from Selection contextual menu item.

Add a main.c file to the project. No need to create a header file for this one so uncheck the Also create a header file box.

Add C File

We’ll reuse this sample code by Holmes Futrell from the SDL/Xcode-iOS/Template/SDL iOS Application/main.c file:

/*
 *  rectangles.c
 *  written by Holmes Futrell
 *  use however you want
 */

#include "SDL.h"
#include <time.h>

#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 480

int
randomInt(int min, int max)
{
    return min + rand() % (max - min + 1);
}

void
render(SDL_Renderer *renderer)
{

    Uint8 r, g, b;

    /* Clear the screen */
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

    /*  Come up with a random rectangle */
    SDL_Rect rect;
    rect.w = randomInt(64, 128);
    rect.h = randomInt(64, 128);
    rect.x = randomInt(0, SCREEN_WIDTH);
    rect.y = randomInt(0, SCREEN_HEIGHT);

    /* Come up with a random color */
    r = randomInt(50, 255);
    g = randomInt(50, 255);
    b = randomInt(50, 255);
    SDL_SetRenderDrawColor(renderer, r, g, b, 255);

    /*  Fill the rectangle in the color */
    SDL_RenderFillRect(renderer, &rect);

    /* update screen */
    SDL_RenderPresent(renderer);
}

int
main(int argc, char *argv[])
{

    SDL_Window *window;
    SDL_Renderer *renderer;
    int done;
    SDL_Event event;

    /* initialize SDL */
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("Could not initialize SDL\n");
        return 1;
    }

    /* seed random number generator */
    srand(time(NULL));

    /* create window and renderer */
    window =
        SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
                         SDL_WINDOW_OPENGL);
    if (!window) {
        printf("Could not initialize Window\n");
        return 1;
    }

    renderer = SDL_CreateRenderer(window, -1, 0);
    if (!renderer) {
        printf("Could not create renderer\n");
        return 1;
    }

    /* Enter render loop, waiting for user to quit */
    done = 0;
    while (!done) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                done = 1;
            }
        }
        render(renderer);
        SDL_Delay(1);
    }

    /* shutdown SDL */
    SDL_Quit();

    return 0;
}

This code displays rectangles with random colors on random areas of the screen. Copy this code to the main.c file.

Finally, set the User Header Search Paths property to the folder where the SDL header files are located. The easiest way to do this is to create a symbolic link that points to the SDL folder inside the HelloSDL project and setting the User Header Search Paths property to SDL/include/.

User Header Search Paths

Make sure HelloSDL is the active scheme in the toolbar then build and run the project to see the dancing rectangles.

Rectangles

Conclusion

As you have seen, C and C++ development in iOS is straightforward through the use of Objective-C++. If you’ve been programming with C or C++ before then it’s easier now to transition to iOS development and leverage your existing skills. Best of all, you can take advantage of existing C/C++ libraries like the powerful SDL with minimal configuration.

I’d love to hear your experiences and opinions on using Objective-C++ in the comments below.

More:
  • Adil Shahzad

    Nice article and good insight..

  • Noflair

    Hi, I post here a comment about the previous article “Using C and C++ Code in an Android App with the NDK” because I can’t comment over there.
    This article is very nice and was helpful for me. Nevertheless I have some troubles with the function SDL_LoadBMP(“image.bmp”). I strictly followed the tutorial, but AndroidStudio gaves me the following error : “SDL_LoadBMP: java.io.FileNotFoundException: image.bmp”. I tried a lot of things to debug this error but they all failed. May you be more clear about how to configure paths or resources or… anything else to get me out of this error ? I don’t really know if image.bmp is well loaded in the app and if it is the case, where it is located. (I work on AndroidStudio 1.5.1, on macOS X (El Capitan)).
    Thank you in advance !

    Noflair

    • Noflair

      Ok, I solved my problem… There is an error in your article. It’s written “To support this, create a folder named asset in…” No, the folder have to be named assets, with an ‘s’ at the end. Now, it works ! :-)

      • Paul Spark

        Did you get the NDK example to work with API 12 on a Mac??? I cannot get the project to sync with API 12. I changed it to API 14 and then it syncs, but it won’t run.

  • Paul Spark

    Hi. I would like to ask a couple of questions about the Android App with NDK posting also. Can you please enable comments or email me direct via my LinkedIn invitation.

Recommended
Sponsors
Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in Mobile, once a week, for free.