Friday, January 25, 2013

A Utility App for iPhone

On the iPhone, the Utility Application template creates an app with a two view controllers. The second view controller’s view is displayed when the user touches a small Info Button in the lower right corner of the first view controller’s view. This allows us to place detailed information in the second view about what is happening in the first view. Let’s see how it works.

Start Xcode, choose “Create a new Xcode project,” and select the Utility Application template. Click Next, name the project UtilityApp, and choose options as shown:

Click Next, choose a location to save the project, and click Create.

Now we’ll set up the XIB files for the two view controllers. First, open MainViewController.xib and drag a UILabel and UIStepper control to the view as shown:

Change the text of the label to “Triangle,” and the properties of the stepper to those shown here:

The application will display information about regular polygons having from 3 to 12 sides.

Open MainViewController.h, and make changes as shown:

#import "FlipsideViewController.h"

@interface MainViewController : UIViewController <FlipsideViewControllerDelegate>

@property (strong, nonatomic) IBOutlet UILabel *lbPolygon;
@property (strong, nonatomic) FlipsideViewController *flipController;

- (IBAction)showInfo:(id)sender;
- (IBAction)stepperChanged:(UIStepper *)sender;

@end

We’ve added properties to the interface for the label (as an outlet) and the FlipsideViewController object itself. (In the template app, the FlipsideViewController is instantiated “just in time,” in our demonstration, we’re going to instantiate it in viewDidLoad.) In addition, we’ve added an action method called stepperChanged: that will respond to a change in value on the stepper control.

Return to MainViewControler.xib, and wire up the lbPolygon label to the label reading “Triangle” and the stepperChanged: method to the Value Changed event of the stepper control:

Notice that the showInfo: method is already wired to the small info button’s Touch Up Inside event. This is provided for us by the template; we won’t change it.

Open MainViewController.m and make these changes to the file :

#import "MainViewController.h"

@interface MainViewController ()
{
    NSArray *polyNames;
}

@end

@implementation MainViewController

@synthesize lbPolygon;
@synthesize flipController;

- (IBAction)stepperChanged:(UIStepper *)sender
{
    self.lbPolygon.text = [polyNames objectAtIndex:sender.value - 3];
    NSString *flipKey = [NSString stringWithFormat:@"%d", (int)sender.value];
    [self.flipController setupFlipsidePropertiesWith:flipKey];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    polyNames = [NSArray arrayWithObjects:
                 @"Triangle", @"Square", @"Pentagon",
                 @"Hexagon", @"Heptagon", @"Octagon",
                 @"Enneagon", @"Decagon", @"Hendecagon",
                 @"Dodecagon", nil];
    self.flipController = [[FlipsideViewController alloc]
                           initWithNibName:@"FlipsideViewController" bundle:nil];
    self.flipController.delegate = self;
    self.flipController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    self.lbPolygon = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

#pragma mark – Flipside View

- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller
{
    [self dismissModalViewControllerAnimated:YES];
}

- (IBAction)showInfo:(id)sender
{    
    [self presentModalViewController:self.flipController animated:YES];
}

@end

In the @interface portion of the implementation file, we’ve declared an NSArray to hold the names of polygons having 3 to 12 sides as NSStrings. The next step is to synthesize the properties.

Now look at viewDidLoad. This method is called after the view is loaded into memory. We set up the polyNames array, then instantiate flipController. There is a protocol declared in FlipsideViewController that we need MainViewController to handle: we set flipController’s delegate to be the object that is created from MainViewController’s class in the AppDelegate. (The delegate method is flipsideViewControllerDidFinish:, defined a bit lower in the file.) After setting the delegate, we define the kind of transition we want when the flipController’s view is displayed. The UIModalTransitionStyleFlipHorizontal transition will give the illusion that the two views are two sides of the same view, flipping about the vertical axis.

The stepperChanged: method simply sets the lbPolygon’s text to the object in the polyNames array corresponding to the current value of the stepper control minus 3. Subtracting 3 is necessary due to the fact that NSArrays (like all C arrays) are zero – based: a stepper value of 3 corresponds to a polyNames index of 0, giving the string “Triangle.” Next we cast the value of the stepper from float to int, and create a string (flipKey) from a formatted string using the int value. We then pass this key to the setupFlipsidePropertiesWith: method of the flipController object.

Open FlipsideViewController.xib and drag three UILabel controls to the view. Change their text, and the text of the title bar as shown here, you will also want to change the color of the labels to contrast with the dark background color.

Open FlipsideViewController.h and make these changes:

#import <UIKit/UIKit.h>

@class FlipsideViewController;

@protocol FlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
@end

@interface FlipsideViewController : UIViewController

@property (weak, nonatomic) id <FlipsideViewControllerDelegate> delegate;
@property (strong, nonatomic) IBOutlet UILabel *lbName;
@property (strong, nonatomic) IBOutlet UILabel *lbSidesAngles;
@property (strong, nonatomic) IBOutlet UILabel *lbAngleMeasure;

- (IBAction)done:(id)sender;
- (void)setupFlipsidePropertiesWith:(NSString *)key;

@end

We‘ve added three properties as outlets for our labels, and also declared the setupFlipsidePropertiesWith: method. Return to FlipsideViewController.xib and wire up the labels to their corresponding outlets:

Also notice that the Done bar button is already wired to the done: method. This is set up by the template, so we won’t alter it.

Open FlipsideViewController.m and make the following alterations:

#import "FlipsideViewController.h"

@interface FlipsideViewController ()
{
    NSDictionary *polyDetail;
}
@end

@implementation FlipsideViewController

@synthesize lbName, lbSidesAngles, lbAngleMeasure;
@synthesize delegate = _delegate;

- (void)setupFlipsidePropertiesWith:(NSString *)key
{
    NSLog(@"Called");
    self.lbName.text = [polyDetail objectForKey:key];
    self.lbSidesAngles.text = [NSString stringWithFormat:@"has %@ sides and %@ angles", key, key];
    self.lbAngleMeasure.text = [NSString stringWithFormat:@"each interior angle is %d degrees", 180 - (360 / [key intValue])];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    polyDetail = [NSDictionary dictionaryWithObjectsAndKeys:
                  @"Triangle", @"3",
                  @"Square", @"4",
                  @"Pentagon", @"5",
                  @"Hexagon", @"6",
                  @"Heptagon", @"7",
                  @"Octagon", @"8",
                  @"Enneagon", @"9",
                  @"Decagon", @"10",
                  @"Hendecagon", @"11",
                  @"Dodecagon", @"12",
                  nil];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

#pragma mark – Actions

- (IBAction)done:(id)sender
{
    [self.delegate flipsideViewControllerDidFinish:self];
}

@end

Again, we set up an iVar in the @interface section, this time to hold an NSDictionary object, the keys of which are string representations of the integers 3 – 12, and the values of which are the names of the polygons. After synthesizing the properties, we proceed with the method definitions.

The viewDidLoad: method instantiates the polyDetail dictionary, so that the setupFlipsidePropertiesWith: method can make use of it. This method sets the text values of the three strings on the view.

The done: method (called when the user taps the Done bar button) just calls the delegate method so that MainViewController can dismiss the flipController.

Run the application, and observe what happens when selecting polygons having a different number of sides.

Notice when running this program that you must show the flipside at least once before touching the stepper control, or the values on the flipside won’t correspond to the values in the main view. (the initial values for the Triangle are hard coded). Think about this behavior, and as an exercise, correct it.


Source : edumobile[dot]org

0 comments:

Post a Comment