Home / iPhone Tips and Tutorials

Creating and Connecting the Outlets and Actions

There are two outlets and three actions that need to be defined in this project. The outlets will be connected identically in each scene, but the actions will be unique for each. Let's review these connections now, starting with the outputs:

  • outputLabel (UILabel): Used for displaying the results of each scene's counter, this label must be connected in each scene.
  • barItem (UITabBarItem): References the tab bar item that was automatically added to each view by the tab bar controller. This connection must be made in each scene.

And the actions:

  • incrementCountFirst: Connected to the Count button in the first scene, this action method updates the first scene's counter.
  • incrementCountSecond: Connected to the Count button in the second scene, this action method updates the second scene's counter.
  • incrementCountThird: Connected to the Count button in the third scene, this action method updates the third scene's counter.

Make sure the first scene is visible in Interface Builder (or just use the Document Outline), and then switch to the Assistant Editor mode.

Adding the Outlets

Control-drag from the label in the center of the first scene to just below the @interface line in GenericViewController.h. When prompted, create a new outlet named outputLabel.

Next, Control-drag from the tab bar item in the first scene to below the outputLabel property. Add another new outlet named barItem.

After creating the outlets for the first scene, connect them to the other two scenes. Control-drag from the second scene's output label and target the outputLabel property in GenericViewController.h. Do the same for the second scene's tab bar item. Repeat this for the third scene, connecting its label and tab bar item to the defined outlets.

Adding the Actions

The actions are unique for each scene, since each scene has a unique counter that needs to be updated. Start in the first scene and Control-dragging from the Count button to below the property definitions in GenericViewController.h. When prompted, create a new action named incrementCountFirst.

Move to the second scene and Control-drag from its button to a line below the incrementCountFirst action. Name this new action incrementCountSecond. Repeat this for the third scene, connecting to a new action named incrementCountThird.

Implementing the Application Logic

Only a little bit of development, and we have a fully functional tab bar application. It won't be particularly useful, but making useful content is your job! Switch back to the Standard Editor now.

We start by establishing the three properties to track the Count button presses in each of three scenes. These are going to be added in the CountingTabBar Controller class and will be named firstCount, secondCount, and thirdCount.

Adding the Push Count Property

Open the CountingTabBarController.h interface file and add three integer property definitions below the @interface line:

@property (nonatomic) int firstCount;
@property (nonatomic) int secondCount;
@property (nonatomic) int thirdCount;

Now, open the CountingTabBarController.m file and add the corresponding @synthesize statements after the @implementation line:

@synthesize firstCount;
@synthesize secondCount;
@synthesize thirdCount;

To access these properties from the GenericViewController class, import the custom tab bar controller's interface file in GenericViewController.h. Add this line following the existing #import statement:

#import "CountingTabBarController.h"

To complete the implementation, we start by creating two methods to update the display within the scenes and then add the actions to increment the counters and call the update methods.

Implementing the Counter Display

Even though the counter differs between scenes, the logic to update the display of all three counter values is entirely the same and is simply an expanded version of the code we used in the previous tutorial. We implement this logic in a new method named updateCounts.

Edit the GenericViewController.h file to declare a method prototype for updateCounts. This isn't strictly necessary if we place the method at the top of the implementation file, but it is good practice and prevents warnings from Xcode. Add the following line after the existing action definitions in GenericViewController.h:

-(void)updateCounts;

Now, add the updateCounts method to the GenericViewController.m file, as shown in Listing-3.

LISTING 13.3 Update the Display Using the Counter Values

1: -(void)updateCounts {
2:     NSString *countString;
3:     countString=[[NSString alloc] initWithFormat:
4: 	    @"First: %d\nSecond: %d\nThird: %d",
5: 	  ((CountingTabBarController *)self.parentViewController).firstCount,
6: 	  ((CountingTabBarController *)self.parentViewController).secondCount,
7: 	  ((CountingTabBarController *)self.parentViewController).thirdCount];
8:     self.outputLabel.text=countString;
9: }

The code begins in line 2 by declaring a countString to hold the formatted version of the output string. Lines 3-7 create the string using the properties stored in the CountingTabBarController instance.

Line 8 outputs the formatted string in the outputLabel.

Incrementing the Tab Bar Item Badge

To increment a scene's tab bar item badge, we read the current value from the badge (badgeValue), convert it to an integer, add 1, convert the new value to a string, and then set the badgeValue to the string. Why is all of that conversion necessary? Because the badgeValue is an NSString, not an integer, so we need to make sure we have a properly formatted string to change it.

Because we have added a uniform barItem property to all the scenes, we only need a single method in the GenericViewController class to handle incrementing the badge value. We'll call this method updateBadge.

Begin by adding a prototype for the new method to GenericViewController.h:

-(void)updateBadge;

Then add the code in Listing-4 to GenericViewController.m.

LISTING-4 Update the Tab Bar Item's Badge

1: -(void)updateBadge {
2:     NSString *badgeCount;
3:     int currentBadge;
4:     currentBadge=[self.barItem.badgeValue intValue];
5:     currentBadge++;
6:     badgeCount=[[NSString alloc] initWithFormat:@"%d",
7:		    currentBadge];
8:     self.barItem.badgeValue=badgeCount;
9: }

Line 2 declares a new string, badgeCount, that will ultimately hold a formatted string to be assigned to the badgeValue property.

Line 3 declares an integer, currentBadge, that will hold the current badge in integer form.

In Line 4, the NSString instance method intValue is used to store the tab bar item's badgeValue, in integer form, in currentBadge.

Line 5 adds one to the current badge count.

Finally, line 6 allocates and initializes the badgeCount string with the value of currentBadge, and line 8 sets the tab bar item's badgeValue property to the new string.

Triggering the Counter Updates

The very last step of this project is to implement the incrementCountFirst, incrementCountSecond, and incrementCountThird methods. If that sounds like a lot, don't worry: Because the code to update the display and the badge is in a separate method, each of these methods is a total of three lines of code, and all of that code, with the exception of a single property, is the same between the three.

The purpose method must update the appropriate counter in the CountingTabBarController class and then call the updateCounts method and updateBadge method to update the interface appropriately. Listing-5 shows a sample implementation for the incrementCountFirst method.

LISTING-5 Add a Method in GenericViewController.m to Update Each Scene's Counter

- (IBAction)incrementCountFirst:(id)sender {
    ((CountingTabBarController *)self.parentViewController).firstCount++;
    [self updateBadge];
    [self updateCounts];
}

Add similar code for each of the other methods: incrementCountSecond and incrementCountThird. The only difference will be the property you increment. Instead of firstCount, you'll use secondCount and thirdCount.

Building the Application

Run the application and switch between the different scenes. Use each scene's Count button to increment its unique counter. Thanks to the decision to store properties in the centrally shared class, CountingTabBarController, all three counts can be accessed and displayed by any scene.

The tab bar items should also show and increment their badges when the Count button is used, providing yet another form of visual feedback that you can give to the user.

Conclusion

This lesson introduced two new view controller classes to your iOS toolkit. The first, the navigation controller, displays a sequence of scenes that are displayed one after the other (and are frequently used to "drill down" into detailed information about something). Navigation controllers also provide an automatic way to back out of a scene and return to the previous scene. The process of moving to a new scene is called pushing, and returning to the previous scene is called popping.

The second view controller, the tab bar controller, is used to create applications with a single unifying bar at the bottom that can be used to switch between different scenes. Each scene, according to Apple's guidelines, should perform a unique function. Unlike the navigation controller, all the scenes managed by a tab bar controller are "random access," meaning that users can switch between whatever tabs they like; there is no preset order.

Both of these controllers present an opportunity for sharing information between the different scenes that they manage by implementing properties and methods on a custom subclass of the controller.

Finally, and possibly the best thing you learned in this lesson, both of these controllers can be implemented almost entirely visually with the Xcode storyboard tools. This is a significant change from earlier releases where the code required to implement these features made them difficult to discuss.

[Previous] [Contents]