views:

517

answers:

4

I am about to create a Cocoa app and I want to ensure that one day I can easily port it to the iPad or even the iPhone. How can I plan for this in advance?

I know I will have to redo all NIBs and probably design a different workflow.

But what about the code? Just replacing every NSsomething with UIsomething won't cut it, right? Any tips on how to make sure now that I won't shoot myself in the foot later?

Thank you!

(The iPad-SDK is under NDA. For the sake of this question just assume i asked about the iPhone, OK? Or think iPhone with a bigger screen.)

A: 

checkout apple.com all apps on the iphone also work on the ipad

SarmenHB
op doesn't already have an iphone app he has a cocoa app.
Surya
oh my mistake i must of miss read it
SarmenHB
+3  A: 

A lot of libraries aren't even supported in Cocoa Touch versus the desktop Cocoa libraries. You need to consider the differences in AppKit versus UIKit. Also, Objective-C does not allow garbage collection on the iPhone. There are many touch events that only exist on the iPhone but not on a desktop. iPhone development is much more restrictive due to the fact that a phone is a very personal device tied to very personal data.

Check out these slides for a better comparison: http://www.slideshare.net/lukhnos/between-cocoa-and-cocoa-touch-a-comparative-introduction

pokstad
+5  A: 

Make sure you strictly uphold the Model-View-Controller separation in your app. The model, especially, should never depend on any controller or view.

In porting to the iPhone/iPod touch/iPad, you'll need to replace most or all of the controllers and all of the NSViews and NSCells. You should be able to keep your CALayer subclasses, if you have any. You may be able to reuse one or two controllers with conditional compilation, if most of a controller will work on both but some parts only work on the Mac or work on both but with completely different APIs. And you should be able to keep the entire model unchanged.

There are probably some more specific pitfalls that an iPhone developer can warn you about, but this is the general rule that holds for any transition from one environment to another. (An example of another environment transition would be making one or more command-line tool equivalents or complements to your app, like xcodebuild, packagemaker, or ibtool.)

Also, look at the Introduction to the Foundation framework reference for figures showing which Foundation classes are Mac- and iPhone-only.

Peter Hosey
+2  A: 

As with any good project layout, you should separate out your UI from your non-UI components. That doesn't just mean on disk layout (though that makes sense as well) but rather using a MVC approach, whereby your controllers (C) know about the Models (M) and the UI (V) is rendered separately.

You can use Key-Value Observing (aka KVO) to set up your models, such that when they fire, it sends around a notification to any registered listeners to update. If you are using XIB to generate your user interfaces, then this is what happens when you bind an object to your display widget(s).

So you can end up with separate XIBs for your iPhone, Mac OS and (later) iPad - though if you resize things correctly, you can have the same XIB for the iPhone and iPad.

Lastly, there are often some cases where you need to inject logic into your models (for example, adding an image to return from a method). In this case, the iPhone and Mac OS have different Image classes. To do this, you can create the following:

MyModel.m         // contains the data, no UI
MyModel+UIImage.m // contains a category for adding the UIImage
MyModel+NSImage.m // contains a category for adding the NSImage

The category looks like this:

@interface Host(UIImage)
-(UIImage *)badge;
@end

@implementation MyModel(UIImage)
-(UIImage *)badge 
{
    if (green)
        return [UIImage imageNamed:@"green.png"];
    if (red)
        return [UIImage imageNamed:@"red.png"];
}
@end
---
@interface Host(NSImage)
-(NSImage *)badge;
@end

@implementation MyModel(NSImage)

-(NSImage *)badge 
{
    if (green)
        return [[NSImage alloc] initWithContentsOfFile: @"green.png"];
    if (red)
        return [[NSImage alloc] initWithContentsOfFile: @"red.png"];
}
@end

This has the added advantage that your unit tests can just load the model (without any image categories being loaded) whereas at runtime your code that needs to process the images (say, in a view controller) can load the model-with-category and load the badge with [model badge] in a transparent way, regardless of which platform it's compiled for.

AlBlue
I check-marked this answer, but all the others were very good as well. Thank you all!
Ron
KVO is good, but there are no Cocoa Bindings on iPhone.
David Dunham