iPad for iPhone Developers 101 in iOS 6: UISplitView Tutorial

This is the first part of a three-part series to help get iPhone Developers up-to-speed with iPad development by first focusing on three of the most useful classes: UISplitView, UIPopoverController, and Custom Input Views. By Ellen Shapiro.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Making Your Model

The next thing you need to do is define a model for the data you want to display. You don’t want to complicate things, so you’re going with a simple model with no data persistence.

First, make a class representing the Monsters you want to display. Go to File\New\File… and select the Cocoa Touch\Objective-C Class template. Name the class Monster, make it a subclass of NSObject. Click Next and then Create.

You’re just going to create a simple class with some instance variables with attributes about each Monster you want to display, and a couple of convenience methods for creating new monsters and accessing the image for the weapon each monster has. Replace Monster.h with the following contents:

#import <Foundation/Foundation.h>

typedef enum {
    Blowgun = 0,
    NinjaStar,
    Fire,
    Sword,
    Smoke,
} Weapon;

@interface Monster : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *description;
@property (nonatomic, strong) NSString *iconName;
@property (nonatomic, assign) Weapon weapon;

//Factory class method to create new monsters
+(Monster *)newMonsterWithName:(NSString *)name description:(NSString *)description 
  iconName:(NSString *)iconName weapon:(Weapon)weapon;

//Convenience instance method to get the UIImage representing the monster's weapon. 
-(UIImage *)weaponImage;
@end

And Monster.m with the following:

#import "Monster.h"
 
@implementation Monster
 
+(Monster *)newMonsterWithName:(NSString *)name description:(NSString *)description 
  iconName:(NSString *)iconName weapon:(Weapon)weapon {
  
    Monster *monster = [[Monster alloc] init];
    monster.name = name;
    monster.description = description;
    monster.iconName = iconName;
    monster.weapon = weapon;
 
    return monster;
}
 
-(UIImage *)weaponImage {

    switch (self.weapon) {
        case Blowgun:
            return [UIImage imageNamed:@"blowgun.png"];
            break;
        case Fire:
            return [UIImage imageNamed:@"fire.png"];
            break;
        case NinjaStar:
            return [UIImage imageNamed:@"ninjastar.png"];
            break;
        case Smoke:
            return [UIImage imageNamed:@"smoke.png"];
            break;
        case Sword:
            return [UIImage imageNamed:@"sword.png"];
        default:
            //Anything not named in the enum.
            return nil;
            break;
    }
}
 
@end

That’s it for defining the model – so let’s hook it up to your left side view!

Displaying the Monster List

Open up LeftViewController.h and add a new instance variable/property for a monsters array as follows:

#import <UIKit/UIKit.h>

@interface LeftViewController : UITableViewController

@property (nonatomic, strong) NSMutableArray *monsters;
@end

Then add a few tweaks to LeftViewController.m to start using this new array:

// At top, under #import
#import "Monster.h"
  
// In numberOfRowsInSection, replace return 10 with:
return [_monsters count];
 
// In cellForRowAtIndexPath, after "Configure the cell..."
Monster *monster = _monsters[indexPath.row];
cell.textLabel.text = monster.name;

That’s it for the table view. Now let’s just populate it with some default monsters!

First, download some art from one of Ray’s Cocos2D games. Drag the folder containing those images into your MathMonsters folder in Xcode, making sure Copy items into destination group’s folder (if needed) is checked, then click Add.

After you add the images, open up LeftViewController.m and replace initWithStyle: with an initWithCoder: method setting up the array of monsters. Note that you are replacing initWithStyle: with initWithCoder: because this class is being loaded from a Storyboard.

-(id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder]) {
        //Initialize the array of monsters for display.
        _monsters = [NSMutableArray array];
        
        //Create monster objects then add them to the array.
        [_monsters addObject:[Monster newMonsterWithName:@"Cat-Bot" description:@"MEE-OW" 
             iconName:@"meetcatbot.png" weapon:Sword]];
        [_monsters addObject:[Monster newMonsterWithName:@"Dog-Bot" description:@"BOW-WOW" 
             iconName:@"meetdogbot.png" weapon:Blowgun]];
        [_monsters addObject:[Monster newMonsterWithName:@"Explode-Bot" 
             description:@"Tick, tick, BOOM!" iconName:@"meetexplodebot.png" weapon:Smoke]];
        [_monsters addObject:[Monster newMonsterWithName:@"Fire-Bot" 
             description:@"Will Make You Steamed" iconName:@"meetfirebot.png" weapon:NinjaStar]];
        [_monsters addObject:[Monster newMonsterWithName:@"Ice-Bot" 
             description:@"Has A Chilling Effect" iconName:@"meeticebot.png" weapon:Fire]];
        [_monsters addObject:[Monster newMonsterWithName:@"Mini-Tomato-Bot" 
             description:@"Extremely Handsome" iconName:@"meetminitomatobot.png" weapon:NinjaStar]];        
    }
    
    return self;
}

Compile and run the app, and if all goes well you should now see the list of bots on the left hand side!

Bots on left hand side of split view

Displaying Bot Details

Next, let’s set up the right hand side so you can see the details for a particular bot.

Open MainStoryboard_iPad.storyboard, go to the Right View Controller and delete the placeholder label you put down earlier.

Using the screenshot below as a guide, drag the following controls into the RightViewController’s view:

RightViewController Layout

  1. A 95×95 UIImageView for displaying the Monster’s image in the upper left hand corner.
  2. A UILabel aligned with the top of the UIIimageView with height 45 and font Helvetica Bold, size 36.
  3. Two UILabels underneath of height 31, with font Helvetica, size 24. One should be aligned with the bottom of the UIImageView, the other should be below it. They should have their leading edges aligned.
  4. A 70×70 IImageView for displaying the weapon image, aligned with the trailing edge of the “Preferred way to Kill” label.

Take care to set up the AutoLayout constraints carefully when you’re constructing this view:

  • Make sure the width and height of the ImageViews are pinned or they’ll stretch on rotation.
  • Make sure the width of the UILabels next to the monster’s image view is not pinned – otherwise your text may get truncated. Having the height pinned is fine (and probably necessary).
  • Try to use Align Edges as much as possible so the views’ positions depend on each other rather than on the superview’s position.

Getting AutoLayout using the proper constraints is especially important for the iPad since apps are required to handle autorotation properly for any orientation.

Note: Auto Layout can be a slippery devil! I highly recommend you check out our Beginning Auto Layout tutorial series if you run into any trouble.

Note: Auto Layout can be a slippery devil! I highly recommend you check out our Beginning Auto Layout tutorial series if you run into any trouble.

Depending on how you lay out your view, you may get slightly different results, but here’s a glance at the constraints that worked when I built it out:

Autolayout Sample Constraints

Ok that’s it for Autolayout for now – let’s hook these views up to some properties. Add some IBOutlets to RightViewController.h as follows:

#import <UIKit/UIKit.h>

@class Monster;
@interface RightViewController : UIViewController

@property (nonatomic, strong) Monster *monster;
@property (nonatomic, weak) IBOutlet UILabel *nameLabel;
@property (nonatomic, weak) IBOutlet UILabel *descriptionLabel;
@property (nonatomic, weak) IBOutlet UIImageView *iconImageView;
@property (nonatomic, weak) IBOutlet UIImageView *weaponImageView;

@end

Here you added properties for the various UI elements you just added which need to dynamically change. You also added a property for the Monster object this view controller should display. Note that the IBOutlets are being retained weakly – they’re also being retained by the xib embedded in the Storyboard.

Then, use the following code in RightViewController.m to display the information from the monster:

#import "RightViewController.h"
#import "Monster.h"

@implementation RightViewController

- (void)viewDidLoad
{
    [self refreshUI];
    [super viewDidLoad];
}

-(void)setMonster:(Monster *)monster
{
    //Make sure you're not setting up the same monster.
    if (_monster != monster) {
        _monster = monster;
        
        //Update the UI to reflect the new monster on the iPad.
        [self refreshUI];
    }
}

-(void)refreshUI
{
    _nameLabel.text = _monster.name;
    _iconImageView.image = [UIImage imageNamed:_monster.iconName];
    _descriptionLabel.text = _monster.description;
    _weaponImageView.image = [_monster weaponImage];
}

@end

Now, go back MainStoryboard_iPad.storyboard, right click the Right View Controller object to display the list of IBOutlets, then drag from the circle at the right of each item to the view to hook up the IBOutlets.

Hooking up IBOutlets to views

Ok, you’re close enough to test this out! Go back to AppDelegate.m and make the following tweaks:

//[Up top, under #import]
#import "LeftViewController.h"
#import "RightViewController.h"
 
//[Inside application:didFinishLaunchingWithOptions:
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;    
UINavigationController *leftNavController = [splitViewController.viewControllers objectAtIndex:0];
LeftViewController *leftViewController = (LeftViewController *)[leftNavController topViewController];
RightViewController *rightViewController = [splitViewController.viewControllers objectAtIndex:1];

Monster *firstMonster = [[leftViewController monsters] objectAtIndex:0];
[rightViewController setMonster:firstMonster];

A split view controller has a property named viewControllers array that has the left and right view controllers inside. The left view controller in your case is actually a navigation controller, so you get the top view controller from that to get your LeftViewController class.

Compile and run the app, and if all goes well you should see some monster details on the right:

Screenshot of finished UISplitViewController

Note that selecting the monsters on the right does absolutely nothing, however. That’s what you’ll do next!

Contributors

Over 300 content creators. Join our team.