This is a fine way of doing things, but if we continued down this path, if we wanted to start with a different view controller for the main menu on startup, we’d have to create it programatically.

Personally, I prefer using Interface Builder whenever possible since it’s faster and less lines of code means less maintenance, so let’s modify the project to start by loading a XIB first – called MainWindow.xib.

Start by opening Supporting Files\main.m, and replace the line that calls UIApplicationMain with the following:

int retVal = UIApplicationMain(argc, argv, nil, nil);

When you pass nil in as the last parameter, it instructs UIKit to load whatever XIB is specified in Info.plist under the NSMainNibFile key. So let’s add that next!

Open your Info.plist, right click in the empty area, and select Add Row from the popuo menu. You can select “Main nib file base name” from the dropdown (or type in the raw key NSMainNibFile).

Then double click in the Value column for this new key, and enter in MainWindow. Your screen should look like the following:

Next step is to create MainWindow.xib! Control-click on your MaskedCal group and select New File. Select iOS\User Interface\Empty, and click Next. Select iPhone for the Device Family, click Next, name the file MainWindow.xib, and click Save.

Click on the new MainWindow.xib file, and you’ll see it load into Interface Builder – mostly blank!

Let’s set this up. First, we need to set the File’s Owner to UIApplication. This is because we’ve told UIApplication to XIB for us on startup, and it passes us a reference to itself.

So click on File’s Owner, and in the Identity Inspector in the sidebar, set the Class to UIApplication.

Next, we need to configure the XIB to create an instance of our Application Delegate on startup. So in the Object library, drag an Object over to the Objects panel:

Then, select the new Object, go to the Identity Inspector, and set the Class to AppDelegate.

One last thing – we have to tell the UIApplication that this new AppDelegate class is its delegate! Do this by control-clicking File’s Owner, and control-dragging the dot next to the delegate onto the App Delegate Object:

w00t! We’ve just set up the following start-up sequence:

In main, UIApplicationMain runs, with the last parameter set to nil.

UIKit then loads the XIB we specified in Info.plist – MainWindow.xib.

When the XIB is loaded, it creates an instance of each object we set up in the XIB. Right now, we have the AppDelegate class in there, so it creates a new AppDelegate class.

Loading the XIB also wires the AppDelegate instance as the delegate of UIApplication.

So now UIApplication will call methods such as applicationDidFinishLaunching on the AppDelegate class!

OK, now let’s finish setting up this XIB. Let’s create the main window in the XIB rather than creating it programatically. Open up AppDelegate.h and modify the UIWindow property to mark it as an IBOutlet:

@property(nonatomic, retain) IBOutlet UIWindow *window;

Also go to AppDelegate.m and comment out the line that was creating it programatically:

Go back to MainWindow.xib and drag a Window from the Object library into the Objects panel. Then control-drag on the App Delegate object, and drag a line from the window outlet to the new Window object:

Compile and run your project, and everything should work just as before, except now you’re using a MainWindow.xib, which will make our next step a bit easier.

Adding a Main Menu View Controller

Instead of starting out with our Cocos2D scene right away, let’s modify this project to start with a different View Controller instead – one we’ll set up as a main menu.

Let’s create the new view controller first. Control-click on the MaskedCal group and select New File. Select iOS\Cocoa Touch\UIViewController subclass, and click Next. Enter UIViewController for Subclass of, make sure Taregeted for iPad is NOT selected, With XIB for user interface IS selected, and click Next. Name the new class MainMenuViewController.m, and click Save.

Click MainMenuViewController.xib, and click on the View under Objects. In the Attributes Inspector, set the Orientation to Landscape.

Next drag an Image View into the view, and make it fill the entire area. Set the Image to Title_bg.png.

Next drag a Round Rect Button into the view. Select the Size Inspector and set X=173, Y=143, Width=135, and Height=62:

Select the Attributes Inspector, set the Type to Custom, and for the Default state set the Image to button_view_uns.png. Then change the State Config to Highlighted, and set the Image to button_view_sel.png.

Repeat this for a second button with the following info:

X=173, Y=213, Width=135, Height=62

Custom type

Default state image: button_about_uns.png

Highlighted state image: button_about_sel.png

One slight code mod we need to make. Open up MainMenuViewController.m and make the following changes:

This will make sure our view controller only rotates to landscape orientation, and that it hides the navigation bar when it starts up.

This is good for now, we’ll finish hooking up the buttons later. Let’s just get this to show up on startup now.

Select MainWindow.xib, and drag a Navigation Controller into the Objects panel. Control-click on the Window, and drag a line from the rootViewControlelr to the new Navigation Controller:

This is setting the first view controller that shows up to be this navigation controller. We’re using a navigation controller to make managing the view controller stack a bit easier.

Next, click the arrow next to the Navigation Controller so it faces down and select the View Controller inside. In the Attributes Inspector, set the NIB Name to MainMenuViewController, and in the Identity Inspector set the Class to MainMenuViewController.

This makes the first item in the Navigation Controller the new Main Menu View Controller we just made!

Almost done – we just need to comment out some old code the Cocos2D template set up for us.

The code inside setupCocos2D is the code we removed from the AppDelegate. It creates an EAGLView, and adds it as a subview of the view controller’s view (at the bottom of the stack). It tells Cocos2D to use the new view, and tells it to run the HelloWorldLayer scene.

Note that since we’re calling this in viewDidLoad, we need to clean things up in viewDidUnload by calling [[CCDirector sharedDirector] end]. Remember views can get unloaded in low memory conditions when they are not visible.

The Cocos2D didn’t create a XIB for the RootViewController, but it is going to be convenient to have one, so let’s go ahead and get that set up too. Control-click on the MaskedCal group, click New File, select iOS\User Interface\Empty, and click Next. Select iPhone for Device Family, click Next, name the new file RootViewController.xib, and click Save.

This will be pretty simple to set up for now:

Select File’s Owner, and in the Identity Inspector set the class to RootViewController.

Then drag a View from the Object Library into the Objects list.

In the Attributes Inspector, set the Orientation to Landscape.

Finally, control-click on File’s Owner, and drag a line from the view outlet to the View you just added.

OK – our RootViewController is fully set up, now we just need to make tapping the button display it!

Open MainMenuViewController.xib, and bring up the Assistant Editor. Make sure it’s set to Automatic, and select the View so MainMenuViewController.h shows up in the Assistant Editor.

Then, control-drag from the View button down below the @interface. Set the Connection to Action, set the name to viewTapped, and click Connect:

Next we need to make an instance variable and property for the RootViewController. Open up MainMenuViewController.h and modify the file to look like the following:

onEnter is called when a scene is first displayed, and onExit is called when it disappears. In these we setup and tear down the gesture recognizers, respectively.

Notice that to create a gesture recognizer you use the following pattern:

Create the gesture recognizer, specifying the target to receive the callback (this scene) and the callback method to be called (which we’ll write next).

Specify any parameters you want on the gesture recognizers, like numberOfTapsRequired, or swipe direction.

Add the gesture recognizer to the view – in this case the openGL view managed by CCDirector.

There’s also one interesting bit you might notice – when we set up the single tap gesture recognizer, we say that for it to count, the double tap gesture recognizer has to fail. If you didn’t have this, the single tap gesture recognizer would be called during the first tap of a double tap, which we don’t want for this app.

As you can see, these are pretty simple methods, and just transition between the scenes. Compile and run, and you should now be able to advance with taps or swipes!

Also, try double tapping and look in the log to verify that it detected the double tap. We’ll implement this next, to make it hide the HUD for a full-screen view of the wallpaper!

Communicating with the RootViewController

You often need to have a way to communicate to the RootViewController from Cocos2D. For example, you might want to display a UI element upon some event. In our case, we want to show or hide the HUD panel on a double tap.

There are multiple ways to do this to avoid dependencies, but the easiest way is to just pass a parameter to the RootViewController to the layer directly.

So basicaly we just pass a reference to the RootViewController through – pretty simple stuff. And on double tap, we call a new method called toggleUI that we’ll write now!

First, we need to add some outlets for the buttons so we can show/hide them. Open up RootViewController.xib, and control-drag from the home button into the assistant editor’s RootViewController.h, right after the @interface. Set the connection to Outlet, set the name to homeButton, and click connect.

This uses UIView animation to make a nice animation to make the buttons slide offscreen/onscreen to show and hide them. If you’re new to UIView animation, you might want to check out the How To Use UIView Animation Tutorial.

That’s it – compile and run, and you should be able to double tap the screen to reveal the wallpapers in their full glory!

Communicating with the Layer

Just like you sometimes need to communicate to the RootViewController from the layer, you also often need to communicate with the layer from the RootViewController.

We’re going to implement tapping the mail button to send an email with the current wallpaper. The RootViewController will contain the code to present the mail composer, but it will need to ask the layer for an UIImage of the currently displayed wallpaper.

Again, there are multiple ways to handle this, but we’re going to take the simple way – just ask the CCDirector for the current running scene. We only have one scene/layer, so we can just get the first layer in the scene and cast it to a HelloWorldLayer, then call whatever methods we want on it.

Let’s first prepare the HelloWorldLayer to have a method to give us the current wallpaper image. Open HelloWorldLayer.h and make the following changes:

Here we use a handy method on CCRenderTexture to convert the current buffer to a UIImage. We also remove the call to visiting the mask sprite, since we don’t really need to demonstrate this anymore, so we’ll just look at the full-screen wallpapers.

Next, open RootViewController.xib, and control-drag from the mail button below the @interface in the assistant editor’s RootViewController.h. Set the connection type to Action, the name to mailTapped, and click Connect.

To display the mail composer, we need to add the MessageUI framework to the project. So select the MaskedCal project in the groups & files tree, select the MaskedCal target, select the Build Phases Tab, expand the Link binary with Libraries section, and click the + button.

Select MessageUI.framework from the dropdown and click Add. Then open RootViewController.h and make the following changes:

Notice how the mailTapped method gets the running scene, pulls out the first child, and knows that it is a HelloWorldLayer. Then it can get the curImage from the layer.

Compile and run, and now you can send a wallpaper you like to a friend! :]

Gratuitous Progress HUDs

If you’ve been running this on your actual device, you might notice that there are certain parts with an annoying delay – setting up Cocos2D for the first time, and compressing image to JPG format for email sending.

When you have long-running operations that the user hast to wait for like this, it’s nice to display an indiator that something is going on to make the app feel more responsive.

One simple way to do this is through a utility class I like called MBProgressHUD. Go ahead and download it, then drag MBProgressHUD.h and MBProgressHUD.m from the unzipped folder into your project. Make sure “Copy items into destination group’s folder (if needed)” is selected, and click Finish.

This just displays a HUD as the viewWallpapers method we wrote earlier (which starts up the RootViewController) gets called. We schedule the viewWallpapers method to run after a slight delay so that the HUD has time to appear before we start running the code to initialize the RootViewController.

This runs the call to UIImageJPEGRepresentation on a background thread, with the HUD animating as this occurs.

Compile and run, and the app should be more responsive!

Gratuitous About Screen

The app is almost complete, except we need an About page! Feel free to skip this if you’re already pretty familiar with how to add new view controllers, but if you need more practice follow along!

Control-click on the MaskedCal group, and select New File. Choose iOS\Cocoa Touch\UIViewController subclass, and click Next. Enter UIViewController for Subclass of, make sure With XIB for user interface is checked, click Next, name the class AboutViewController.m, and click Save.

Click on AboutViewController.xib and make the following changes:

Select the View, and in the Attributes Inspector set the Orientation to Landscape.

Drag a UIImageView to fill the View and set the image to About_page_bg.jpg

Drag a UILabel into the View, set X=49, Y=132, Width=382, Height=104, Text Color to White, and Font to Heiti SC Light 16.0, Txt Alignment to Center, # of Lines to 0 (means unlimited).

Change the text to: “Vicki works with her husband to create iPhone and iPad apps. Find more of her wallpapers on her website, vickiwenderlich.com, as well as free art for app developers and tutorials for artists.”

At this point your screen should look like this:

Then switch to AboutViewController.m and replace the shouldAutorotateToInterfaceOrienation with the following plus a new method:

Then select MainMenuViewController.xib and control-drag from the About utton into the assistant editor’s MainMenuViewController.h. Set the Connection type to action, the name to aboutTapped, and click Connect.

Then switch to MainMenuViewController.m and make the following changes:

Almost done – one more minor tweak for style. Open up MainWindow.xib and select the Navitation Controller\Navigation Bar. Select the Tint color, and set R=168, G=215, B=224 for a nice teal color to match the rest of the app:

Also select the Navigation Controller \ Main Menu View Controller\Navigation Item and set the Title to Home.

That’s it! Compile and run, and now the app is complete – with an About page and all!

Where To Go From Here?

Here is the complete example project with all of the code from the above tutorial series.

At this point, you should be familiar with the basics of how to integrate Cocos2D with UIKit. If you have any questions, comments, or suggestions, please join the forum discussion below!

Ray is part of a great team - the raywenderlich.com team, a group of over 100 developers and editors from across the world. He and the rest of the team are passionate both about making apps and teaching others the techniques to make them.

When Ray’s not programming, he’s probably playing video games, role playing games, or board games.

I am trying to integrate UIView to a simple hello world Coccos2d project.Im actually following the following this tutorial i.e.,http://www.raywenderlich.com/4817/how-to-integrate-cocos2d-and-uikit ,
but I'm getting this error
OpenGL error 0x0501 in -[EAGLView swapBuffers].
Can any one help?

.Thanks for this great tutorial.But i have a problem.I am trying to integrate UIView to a simple hello world Coccos2d project.My aim is to keep a menu screen for the hello world project.Im actually following the following this tutorial i.e.,http://www.raywenderlich.com/4817/how-to-integrate-cocos2d-and-uikit ,
but I'm getting this error
OpenGL error 0x0501 in -[EAGLView swapBuffers].
Can any one help?[/quote]