Super Art Studio

Recent site activity

中文首页‎ > ‎科技热点‎ > ‎iPhone‎ > ‎

I Hate the iPhone SDK

Background Application

posted Aug 29, 2008 4:13 AM by Leo - www.superarts.org -

Underground iPhone app developers have been getting away with this for awhile, but I haven't yet seen an example that uses the regular iPhone SDK. Even if you're a pretty experienced developer, it's probably not immediately apparent how the "magic" of bootstrapping a Cocoa Touch app works. 

Here's a quick guide how to make your iPhone app run forever. Keep in mind, while this works in the simulator, I have no idea how it'll work on a real iPhone. I also doubt that Apple would be too happy about distributing an app like this through their store.

First... Make a new project. For this example, I use the  Cocoa Touch Toolbar template.

Next, we create a new class. I choose to make it an "NSObject subclass" (we're going to change it in a second anyway), and I name the file ZombieApplication.m (I checked the "Also create ZombieApplication.h" as well).



After that, we'll adjust the ZombieApplication class so that it derives from UIApplication, and overrides the applicationSuspend: event.  Edit your ZombieApplication.m/.h files to look like this:
 


So great, you've created a UIApplication subclass that lets you live forever. Unfortunately, by default, it seems that the Cocoa Touch framework instantiates UIApplication instead of your new subclass. We need to change that behavior. Open up main.m and look for the line like:

    

int retVal = UIApplicationMain(argc, argv, nil@"ZombieAppDelegate");

 
In this case, my XCode project is called Zombie. So my app delegate is automatically named "ZombieAppDelegate", which is specified as the last parameter to UIApplicationMain(). Cocoa Touch will automatically instantiate the app delegate class based on the name you supply here.  But alas, we don't really care about the app delegate. It's already instantiating ours, and we can't zombify our application with just an app delegate. 

The trick here is the third parameter, which by default will be nil. This parameter specifies the name of the application class to instantiate. Ah-Ha! This is what we want. Simply change this third parameter to be the name of your UIApplication subclass. In my case, I changed it to:


int retVal = UIApplicationMain(argc, argv, @"ZombieApplication"@"ZombieAppDelegate");


That should be all you have to do. Of course, the iPhone SDK is never that simple. If you are running the SDK beta 2, and you try to compile this. You'll be greeted with a multitude of fun errors. In fact, this template, even before we modified it, wouldn't have compiled at all. Thanks Apple, for changing UIToolbarController to UITabBarController, without updating the documentation or the template. 

To rectify the situation, crack open your app delegate .h (In my case it's called ZombieAppDelegate.h) and replace all instances of UIToolbarController withUITabBarController. Now crack open the corresponding .m file and do the same, but also replace all instances of viewController.toolbarItem.image withviewController.tabBarItem.image

And Viola! Our App lives. 


To prove it's working, pick one of the colors on the tab bar and hit the button on the simulator to shoot you back to the home screen. When you relaunch the app, you'll see that it's retained your selection. You'll notice also that the debugger won't detach after you get back to the home screen (since the app is still running). 

Interface Builder

posted Aug 29, 2008 4:12 AM by Leo - www.superarts.org -

Beta 2 of the iPhone SDK made a big splash when it was announced that Interface Builder, Apple's visual gui design tool, would finally be available for iPhone developers. Unfortunately for those of us who, god forbid, tried to actually use it, no documentation was provided, save some hints in the release notes.

After messing around for a few days, I think I have a pretty good idea of the "right" way to use Interface Builder for iPhone development. A couple of blogs/forums are throwing around a Hello World example where they load the nib programatically, and subclass UIView to handle events. That will probably work, but I think this way is much cleaner.

With this method, you'll be able to take advantage of the MVC paradigm that the SDK expects you to use, and you'll be able to instantiate your UI and hook up events with nearly no code. 

My one warning is that GUIs built with Interface Builder have some pretty serious flaws. In my pretty shallow tests, the biggest thing I noticed was that Interface Builder doesn't provide any way to change the text color of any widgets. This wouldn't be such a big deal, but UILabels you create in Interface Builder don't respond to the setTextColor: message either. Hopefully I'm doing something wrong, and someone can call me out, but I suspect this is a bug, because UILabels seem to respond fine to setting the font size and face.  I would suggest maybe waiting for the next version of the SDK until you start building apps with Interface Builder. 

That being said, here is a guide to creating a small demo app with a UIButton that, when clicked, sets a UILabel text to read "Hello World".

- First, fire up XCode and hit File->New Project...
- Select "Cocoa Touch Application" and call the project HelloWorld
- When the project window opens up, expand the Classes group under the Groups & Files pane located on the right side of the project window.
- Select MyView.h and MyView.m and press delete. Click the "Also Move to Trash" button. We don't need these classes, we're going to make our UIView in IB.


-Open up the HelloWorldAppDelegate.h file. The code will look like this:

#import <UIKit/UIKit.h>


@class MyView;


@interface HelloWorldAppDelegate : NSObject {

    UIWindow *window;

    MyView *contentView;

}


@property (nonatomicretain) UIWindow *window;

@property (nonatomicretain) MyView *contentView;


@end

First, remove all the properties, and the references to MyView, since we're not using it:

#import <UIKit/UIKit.h>


@interface HelloWorldAppDelegate : NSObject {

    UIWindow *window;

}


@end

Next, we need to make outlets for us to connect our AppDelegate class with our UI in interface builder. We use the IBOutlet keyword to mark window as an outlet:


#import <UIKit/UIKit.h>


@interface HelloWorldAppDelegate : NSObject {

   IBOutlet UIWindow *window;

}


@end

Finally, we also want to add an outlet for a UIViewController to our project, which will be in control of events for UIView we will make:

#import <UIKit/UIKit.h>


@interface HelloWorldAppDelegate : NSObject {

   IBOutlet UIWindow *window;

   IBOutlet UIViewController *viewController;

}


@end



- Now that we have our header ready to plug in some outlets, fire up Interface Builder (I usually just type it into spotlight, and then click the icon)
- The "Choose a template" dialog should pop up. Select the "Empty" option.
- Now, save the interface builder project: Click File->Save As..., then navigate to your project's folder (HelloWorld) and give your IB Project the name MainUI
- When asked if you would like to add the file to your XCode project, click the checkbox next to your HelloWorld project, and click Add


-Click Tools->Inspector to make the Inspector viewable. Then, click on the (i) button on the top-right of the inspector window. In your project window, click the cube labeled File's Owner. Now, in the Inspector window, type UIApplication into the class field. 


-Drag an Object cube from the library into your project. In the inspector, set class asHelloWorldAppDelegate
It should be in the drop-down.
 

-Now, set the "Hello World App Delegate" to be a delegate of "File's Owner" (our UIApplication). 
To do this: Right click on "File's Owner" and drag the hole next to delegate into the "Hello World App Delegate" icon.


-Next, from the library, drag in a View Controller, a Window, and a UIView


-Double click the view to bring up the view designer. Drag a UIButton and a UILabel onto your view.
-Using the Inspector, change the title of the button to be Touch Me


-In the project window, select your view. In the inspector, make sure "User Interaction Enabled" is checked.

-In the project window, select your view controller. In the inspector, click the identity button (i), in the upper right. Input a class name of HelloViewController
-Add a class outlet: label (of type UILabel) and add an action called buttonClicked:


Interface Builder is going to generate this class for us. With our view controller still selected, pick File->Write Class Files..., and click save. Choose to add these classes to your project when prompted, by clicking the checkbox next to the HelloWorld Project, and clicking Add.

-Jump back into XCode and select HelloViewController.h
Interface Builder generates incomplete (actually, downright wrong) code, so we'll have to make a few changes. Adjust the import to UIKit/UIKit.h, intead of Cocoa/Cocoa.h, and put in the code to subclass UIViewController. When you're done, it should look like this:

#import <UIKit/UIKit.h>


@interface HelloViewController : UIViewController {

    IBOutlet UILabel *label;

}

- (IBAction)buttonClicked:(id)sender;

@end


-Save your changes, and switch back to IB

-Connect the label outlet on the view controller to the label on your view


-Connect the button's "touch up inside" event to your view controller buttonClicked: action


-Connect our view to our view controller's view outlet to our view:


-Connect our App Delegate's viewController outlet to our view controller, and the window outlet to our window:
 

-Save your changes and switch back to XCode

-In XCode select the HelloViewController.m file. It should already have a method for the buttonClicked: action. We'll just add some code to chagne the label text here:
 #import "HelloViewController.h"


@implementation HelloViewController

- (IBAction)buttonClicked:(id)sender {

    [label setText:@"Hello World!"];

}

@end


- Next, select your HelloWorldAppDelegate.m
There is a lot of extraneous code in here from the original template. We remove the @synthesize lines (they deal with the properties of the class we removed earlier), the #import for the MyView.h that we deleted, and fix the dealloc code to free our outlets.  In the applicationDidFinishLaunching: method, we do the minimum necessary to show our view. The final code in HelloWorldAppDelegate.m:

#import "HelloWorldAppDelegate.h"


@implementation HelloWorldAppDelegate


- (void)applicationDidFinishLaunching:(UIApplication *)application {

[window addSubview:viewController.view];

[window makeKeyAndVisible];

}


- (void)dealloc {

[window release];

[viewController release];

[super dealloc];

}


@end


Next, we need to edit main.m in our project. Notice the line
  int retVal = UIApplicationMain(argc, argv, nil@"HelloWorldAppDelegate");
To tell UIApplicationMain to make our gui from the xib file, we replace it with:
  int retVal = UIApplicationMain(argc, argv, nilnil);


Finally, we have to add the lines inside our Info.plist, inside <dict> tags:

<key>NSMainNibFile</key>

<string>MainUI</string>



Finally, the coup de grace, click 'Build and Go' and....
This should really be easier...

Edit: If you want to grab a copy of the completed HelloWorld app source, you can grab it here

‹ Prev    1-2 of 2    Next ›