Adapting and sharing code for iOS and OS X

So now that I have started writing OS X application for the mac and there are obviously a lot of similarity with iOS I decided to write some companion app on OS X for my new project TennisStats.

Most of the code is quite abstracted between the UI and the data logic behind, which helped a lot, but I embarked upon sharing my main plotting library inherited from ConnectStats. What will it take to share that library between iOS and OS X?

Compiler Macros

The first thing was to figure out the right macros to predicate the code between the two OS. TARGET_OS_IPHONE and TARGET_OS_MAC are define and the one to use here. Though one thing I quickly learned was the really I should use TARGET_OS_IPHONE as TARGET_OS_MAC is defined both for OS X and iOS.

The key library can then be imported with #if. Note that CoreGraphics seems to be the same across both.

#if TARGET_OS_IPHONE
#import 
#import 
#else
#import 
#import 
#endif
#import 

UI and NS prefix

A lot of the classes prefixed by UI provided by apple on iOS have equivalent named with NS. Was it going to be as easy as using one for the other?

Brief look at the class reference showed a lot of similarity and iOS was derived from OS X, so why not… So I started to add the following typedefs

#if TARGET_OS_IPHONE
#define RZColor UIColor
#define RZFont UIFont
#define RZImage UIImage
#define RZView UIView
#define RZBezierPath UIBezierPath
#else
#define RZColor NSColor
#define RZFont NSFont
#define RZImage NSImage
#define RZView NSView
#define RZBezierPath NSBezierPath
#endif

And the replace each instance of UIColor, UIView, etc with the equivalent version prefixed with RZ. Most of it compiled! NSBezierPath has the most differences, and I had to write an extension to provide the following functions

extern CGContextRef UIGraphicsGetCurrentContext();
extern NSString * NSStringFromCGPoint(CGPoint point);

@interface NSBezierPath (QuartzHelper)

+(NSBezierPath*)bezierPathWithBezierPath:(NSBezierPath*)other;
+ (NSBezierPath *)bezierPathWithCGPath:(CGPathRef)CGPath;
-(CGPathRef)CGPath;
-(void)addLineToPoint:(CGPoint)point;

@end

So now it compiles… Will it just work and is that easy?

Ooops

Oops… A new issue to worry about, the coordinates in OS X and iOS have their Y axis inverted… Luckily I had quite nicely abstracted the CGPoint calculation in a Geometry class… So a key target predicate

-(CGPoint)pointForX:(CGFloat)x andY:(CGFloat)y{
    
#if TARGET_OS_IPHONE
    return CGPointMake( (   _graphDataRect.origin.x + (x-_dataXYRect.origin.x)* _horizontalScaling),
                       _graphDataRect.origin.y+_graphDataRect.size.height - (y - _dataXYRect.origin.y) * _verticalScaling);
#else
    return CGPointMake( (   _graphDataRect.origin.x + (x-_dataXYRect.origin.x)* _horizontalScaling),
                       _graphDataRect.origin.y+ (y-_dataXYRect.origin.y) * _verticalScaling);
#endif
}

And a few more around the title and axis location, et voila!

Better

In Summary

It was much easier than I expected. And definitely makes the thought of building an OS X companion app very realistic…

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.