Tuesday, August 11, 2009

Abstracting iPhone code into C++

iPhone development is quite the darling of the world right now. Everyday there are various applications launched on the app store, and everyday there are many more people learning to develop on the iPhone.

And of course, such hype sure got me interested too.

The primary programming language of iPhone application development is to use Objective C. I took a dive in it. I liked it. Almost. The seperation of implementation and interface, private 'modules', named arguments and properties were all very helpful.

But my biggest gripe is the 'reference counting' memory mechanism I have to deal with. It is a good idea, along with the memory pool and auto-release idea. But faced with the huge API library list, I simply do not have the confidence to manage it properly.

And the next big gripe is that you had to be on a Mac to develop for it (or as far as I know).

And then someone told me about using C++ with Objective C. So I had to hunt around information for it. But there really is not that much information on the internet about it. All they provided were basic information.

So, was C++ with iPhone information lacking? Or was it really that simple and not much need to be mentioned?

The example provided in Apple's "The Objective C 2.0 Programming Language" showed how to mix C++ in Objective C, but honestly, it gave me more doubts instead.

The best way out is via experiments. This is what I did.

1. Declare a C++ class, with .h and .cpp files, with virtual methods.
2. Derive a C++ class from above, overriding the virtual methods.
3. Write out some string in the constructor and destructor of the C++ class.
4. Declare the derived C++ class in the Objective C class as a local variable.
5. Declare a pointer to the C++ class in Objective C class, and use new/delete on it to instantiate the derived class.
6. Invoke the virtual methods on both the local variable and the pointers.

The result of this experiment prove that:

1. An iPhone application is able to compile cpp files alongside with m and mm files.
2. The mm extension is required to use C++ in the file.
3. An iPhone application obey C++ virtual method rules.
4. An iPhone application correctly invokes C++ destructors.

Turned out it really is that simple.

So we have answered the question from Objective C to C++. But how about the other way? There will definitely be times when an application logic in C++ might have to call on some Objective C API, either because the Objective C API are better, or that they are the only way.

After much googling, turned out that the only way for a cpp file (note the extension) to invoke Objective C API, is through C wrapper. Wrap the Objective C API in C style functions, and then call them in C++.

So we had covered both directions. Objective C -> C/C++, and C/C++ -> Objective C.

The next logical step would be on abstracting enough of the application into a core C++ Application class. Why such an approach?

1. I am very much more comfortable with C++ compared to Objective C (primary reason).
2. Having the core application logic in C++ allows me to port the same logic to be run on Windows and Linux, if need be. At least if there is to be a fellow developer who does not have a Mac, he could do so in Windows.

But of course, I think an important guideline is to be obeyed. This has no actual experiment results to back it up, but is simply an intuation from past cross language developments.

Obey language boundaries. Treat each boundary API call as seperate object space. Meaning, if an object is allocated memory in Objective C, avoid releasing the memory in C++ code. Do so only by calling an Objective C function. Of course, the primary driving theoratical reason is the memory pool in Objective C. And that also mean that, try not to hang on to objects from Objective C for longer than necessary in C++, unless you are absolutely certain of the lifespan of the Objective C object.

Sorry for the side-track, and now back to the abstraction. To help in the abstraction, an outline of an application lifecycle and its possible events could be help. At the most basic level, these are the possible events and lifecycle.

1. Create Application
2. Receive request to render
3. Receive request for input
4. Destroy Application

I am going to assume basic iPhone knowledge, and paste the snippet of the iPhone UIView here. This is actually the bridge from Objective C into our core C++ application.

@implementation View
- (id)initWithFrame:(CGRect)frame {
     if (self = [super initWithFrame:frame]) {
          CGRect rect = self.bounds;
          application = new Application(rect.size.width, rect.size.height);
          [self startTimer];
     }
     return self;
}
- (void)layoutSubviews {
     application->resize();
     application->render();
}
- (void)onTimer {
     application->tick();
     application->render();
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
     UITouch *touch = [touches anyObject];
     CGPoint tapPoint = [touch locationInView:self];
    
     application->onTouchBegan(tapPoint.x, tapPoint.y);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
     UITouch *touch = [touches anyObject];
     CGPoint tapPoint = [touch locationInView:self];
    
     application->onTouchMoved(tapPoint.x, tapPoint.y);
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
     UITouch *touch = [touches anyObject];
     CGPoint tapPoint = [touch locationInView:self];
     int tapCount = [touch tapCount];
    
     application->onTouchEnded(tapPoint.x, tapPoint.y, tapCount);
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
     application->onTouchCancelled();
}
- (void)dealloc {
     [self stopTimer];
     delete application;
     [super dealloc];
}
@end

And a bare bone snippet of our C++ Application class:

class Application {
     public :
     explicit Application(const float newWidth, const float newHeight);
     ~Application();
    
     void resize(void *const windowContext);
     void render();
     void tick();
    
     void onTouchBegan(const int touchID, const float x, const float y);
     void onTouchMoved(const float x, const float y);
     void onTouchEnded(const float x, const float y, const int tapCount)
     void onTouchCancelled();
};

I have purposefully left out OpenGL ES related code, as that is not the focus of this post.

There, now we can concentrate most of our time in C++ development!

Link to bare bone implementation project

blog comments powered by Disqus