Home > 2011 Winter DPS913 > DPS913 APD601 Lab 2 guidance

DPS913 APD601 Lab 2 guidance

January 25, 2011 Leave a comment Go to comments

This post has information that will guide you through your work on Lab 2.

.

Comments about the design

We suggest that you keep your design simple. Although you may consider creating a “bus route” model class, with properties for the route code, the route name, the ticket price, and the number of available seats, don’t do it yet.

Instead, use simple arrays, because you need to gain experience with them.

You really need only two arrays: One for the ticket prices, and one for the available seats. Each array will have four elements – one for each bus route. We’ll also use a segmented control, with four segments, for the four bus routes.

We will logically associate the positions of the segmented control and the array elements ourselves. Our design will be very static, so it’s safe to do it. This simple design will allow you to learn the concepts you have to learn, and still get lots of practice creating an iOS application.

The following table shows the logical associations that WE will maintain ourselves:

Bus route Segmented control segment Array for
ticket prices
Array for
available seats
Toronto to
Barrie
0 – BAR 28.80 36
Toronto to
Peterborough
1 – PTR 39.35 36
Toronto to
Ottawa
2 – OTT 109.30 36
Toronto to
Sault Ste. Marie
3 – SSM 156.80 36

When the user wants to select the “Toronto to Barrie” bus route, they will tap the BAR segment. That’s segment 0 (zero).

This number becomes our element number for the arrays: Element 0 (zero) of the ticket prices array has the Barrie ticket price in it, and, element 0 (zero) of the available seats array has the number of seats available on the Barrie bus route.

.

So, the segmented control’s selectedSegmentIndex property will drive the operation of the program.

Only the available seats array has values that will change during the use of our program. Therefore, you will use an NSMutableArray. The ticket prices array can be an NSArray.

.

Getting started

In the professor’s working example, a “View-based Application” template was used, and you should do the same.

To get started, you should consider creating the user interface first. That will help you decide about which (view controller) properties are needed. For the text labels, enter descriptive text for now. (As you write code, you can always set the label’s text property with status information and results.)

As you have learned, the UIPickerView control requires a data source and a delegate. The purpose of the picker will be to enable the user to select the number of tickets to be sold for the selected bus route.

Therefore, in the suggested design, you should create a (mutable) array that will act as the picker’s data source. This will enable you to

  1. generate an array with the number of elements that matches a bus route’s available seats, and
  2. format the picker’s visible text entries in the way that you want.

.

You can then re-generate the array when the user picks a different route, or when they “buy” tickets.

The view controller class can be used as the data source and delegate. Therefore, it will have the methods that enable the picker to get its visible data and provide selection notifications. It will also have methods to handle the button tap, the segmented control tap, and maybe a few other convenience methods.

So, here’s a list of the objects that your project should have:

  • Segmented control (UI)
  • Picker view control (UI)
  • Labels for status and info (UI)
  • A button control to “buy” tickets (UI)
  • Array, 4 elements, for the ticket prices (on each bus route)
  • Array, mutable, 4 elements, for the number of available seats (on each bus route)
  • Array, mutable, as a picker data source, with a variable number of elements
  • Methods for the data source and delegate
  • Methods for other user operations

.

The arrays can be declared properties, which will simplify your syntax.

.

Adding numeric elements to an array

We have learned that the Cocoa collection classes, including NSArray, NSDictionary, and NSSet, require “objects” in their collections. This means that our NSArray (or NSMutableArray) objects must contain “object” elements.

We intend to store numbers – C scalar float and int types – in the “ticket price” and “available seats” arrays. How do we do this?

The solution is to “box” the float or int in an NSNumber, which is an object. To convert back from an object to a float or an int, we use a <type>Value message.

.

Storing numbers into an NSArray

Use this coding pattern:

NSMutableArray *myArray = [[NSMutableArray alloc] init];
// Now… add a float and an int to the array
[myArray addObject:[NSNumber numberWithFloat:3.456f]];
[myArray addObject:[NSNumber numberWithInt:789]];

.

Note that you can also use an NSArray, and one of its class methods, to create a small array in one line of code.

.

Getting numbers from objects in an NSArray

Assume that the code above created a two-element array. Use this coding pattern to get the numbers out:

float myFlt = [[myArray objectAtIndex:0] floatValue];
int myInt = [[myArray objectAtIndex:1] intValue];
float result = myFlt * myInt;

.

For more details, see the Wikipedia article on boxing and unboxing.

.

Declaring methods for the picker

We learned the following during a recent lecture section: The view controller will be the data source and delegate for the picker. What methods do we need to implement? The UIPickerView documentation tells us that the delegate must adopt the UIPickerViewDelegate protocol. When we look at the UIPickerViewDelegate documentation, we see that the following must be implemented:

  • pickerView:titleForRow:forComponent:

.

There is one optional method that we must implement:

  • pickerView:didSelectRow:inComponent:

.

The documentation also says that the data source must adopt the UIPickerViewDataSource protocol. When we look at the UIPickerViewDataSource documentation, we see that the following must be implemented:

  • numberOfComponentsInPickerView:
  • pickerView:numberOfRowsInComponent:

.

Reminder: When you implement methods from a superclass or a delegate (or a data source), you do not have to declare the method signatures in the interface (.h). You simply implement the method in the implementation (.m). The Xcode editor will help you with the method signature: Type a dash, a space, a few letters from the method name, and press Esc to choose from the pop-up list of members.

.

Other methods

We will need methods that handle the segmented control tap and the button tap.

Also, it would be a good idea to have a method that would rebuild the data source for the picker. Both of the methods just mentioned (segmented control tap, and button tap) would require that the data source be rebuilt/regenerated. Therefore, create a method to do this, and call it from the two user-action methods.

.

Next – make the user interface work

Now that we have the planning done, it’s time to do the programming. We suggest that you complete the user interface by making it work.

.

Initialize the arrays for ticket prices and available seats

Next, you could implement the pickerView:didSelectRow:inComponent: method, but the picker doesn’t show up in the user interface. It won’t show up until we create the data source.

Before creating the data source, let’s create the arrays for the ticket prices and the available seats. Where does this code go? We will put the code in the view controller. Where exactly? Well, we want the data to be available just before the view loads. Why? The view needs access to the data, so that it can (among other tasks) build the picker.

Therefore, implement the superclass’s awakeFromNib: method. (See the NSObject documentation for its signature.) The awakeFromNib: method will run once in our application. (Remember that when implementing a superclass method, one of the first things you do is call the superclass’s method of the same name. In our case, it’s: [super awakeFromNib];)

Then, initialize the arrays. We suggest that you use one of the factory/convenience methods to build the array. Remember: When initializing an array with a factory/convenience method, the last element must be nil.

When you initialize an array, send it the retain message. Otherwise, it will be deallocated at the end of the awakeFromNib code block, and your app will not work.

.

At this point, make sure the arrays get built by using the NSLog function (or reporting to the user interface).

Now, you can create the data source (array) for the number of available seats for the bus route. Before you do, decide what segment will be selected when the program starts. That will determine the selected bus route, and the ticket price. You’ll need that information, so that you can build the data source in a way that matches the example shown in the Lab 2 specifications.

Where do you create the data source array? In the awakeFromNib: method? No. As stated above, you’ll want to rebuild the data source whenever the segmented control selection changes, and when the “Buy” button is tapped. Therefore, it needs to go somewhere else.

The suggested approach is to create a method (maybe called “buildThePicker”) that does this job. Then, it can be called any time it is needed (including the first load/launch of the app). The method could have an argument, so that the selected bus route value can be passed in. Then, the method will create the array, by looking in the other arrays (for the ticket price and available seats).

Tip: Include “0” (zero) in the picker’s data source array. That way, your index matches the visible row value. This provides a good default/initial value for the number of tickets to be purchased when a route selection changes. It also enables you to clearly show that there are zero tickets available when all have been sold on a bus route.

.

Making all the moving parts work correctly

At this point, you should have all the building blocks in place.

We know that selecting a different segment should result in a picker data source rebuild. If the picker is at a non-zero row, what should the desired behaviour be? We suggest that you spin back the picker to row zero. There’s a picker method for that: selectRow:inComponent:animated:.

Similarly, after a “purchase” is completed, what should happen to the picker? Should its selected row stay at the row for the number of tickets purchased? We suggest that again, you spin it back to row zero.

In both situations, you will be interested in what you need to do, so that the right data shows up in the picker. Here’s what to do:

Just before you rebuild the picker’s data source array, you must remove all of the array elements/object. Look in the NSMutableArray class reference document for a method that would do that.

After the picker’s data source array has been successfully rebuilt, you want to tell the picker to reload. Look in the UIPickerView class reference document for an instance method that would enable you to reload.

.

Good luck!

.


Advertisements
Categories: 2011 Winter DPS913
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: