Home > 2011 Fall DPS913, iOS, iOS Cocoa Touch > Introduction to Cocoa collection classes

Introduction to Cocoa collection classes

September 19, 2011 Leave a comment Go to comments

Cocoa has classes that hold collections of objects. We work with two today (array, dictionary) and later, we will work with a third (set).

.

This post was most recently updated in September 2013.

.

The Apple documentation offers us two accessible introductions to Cocoa collection classes. I won’t bother rewording them here – instead, I’ll link you to them, and we’ll cover the concepts during the lecture.

.

Cocoa collections

From the Cocoa Core Competencies list of topics:

Collections

From the iOS Dev Center reference documentation:

Collections Programming Topics

Go through the Arrays… and Dictionaries… topics.

Also, go through this topic: Fast Enumeration

Study the images below. All of the coloured rectangles are objects. As suggested by the NSArray and NSDictionary rectangles, these objects simply maintain pointers to existing objects (the coloured circles and rectangles).

.

.

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.

If we intend to store numbers – C scalar float and int types – in an array, 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 its literal syntax, or 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.

.

Reminder about the Model-View-Controller (MVC) app design pattern

We introduced the Model-View-Controller (MVC) app design pattern in the first lecture session.

The apps that you created in the first two weeks of the course included a view and a controller. There typically was no model.

The apps that you will create now and in the future will also include a model.

The simple apps will often create a model in a view controller, and the model objects will typically be simple-to-understand types (e.g. strings, or an array of strings).

Apps that are more complex will include model classes that you define. Some of your model objects may also use frameworks (e.g. Core Data) or facilities (e.g. web service) that provide the structure and definition of the model, and ways to access and maintain the model objects.

A more in-depth treatment of model objects is in a post titled “Model object design for iOS apps“. You can skim the post now, but we will spend more time with it in the next few weeks.

.

Reminder about events

Before we continue, you are reminded that the Cocoa runtime is in control when your app is running. Events that happen in the environment, and while the user interacts with the device, are passed on to your application by the Cocoa runtime.

It is very important to know this as you study the next example, where an event that happens (i.e. the loading of a user interface object) causes a series of messages to be sent to your view controller (which is acting as a delegate).

.

Reminder about a delegate

In addition, you are reminded about a delegate: A delegate is a “helper” object, which has methods that can be called from another object.

It is very common to designate a view controller as a delegate for user interface objects. We use a delegate in this situation because we cannot write custom code in the nib file.

It is also very important to know this as you study the next example, where your view controller is configured as a delegate for a user interface object.

.

Simple example app – Picker

The “Picker” example app works with an array again, but with a twist this time. The array is a data source for a picker in the user interface.
.

How a  picker (UIPickerView) works

A picker needs a “delegate” and a “data source” to work properly. (Soon, you will use a table view, which also works in a similar way.

A picker is an object that is (in our situation) declared in a nib. On other platforms, it is possible to enter initial values for the picker’s row. Not on this platform. We cannot write code in a nib, so we write code in the delegate and the data source. In our picker example, the one and only view controller will adopt the picker’s delegate and data source protocols.

The interesting thing about the picker (and the table view) is that it enables us to simply create a data source (typically an array), and the instantiation of the picker, when it loads during the view-loading phase, does most of the UI-building work on its own.

When the picker loads, it asks these questions:

1. How many components are in this picker view? (As you will learn, a picker can have one or more spinning dials; each one is called a “component”.)

For each component…

2. How many rows are in the component?

For each row…

3. What (text) should be displayed?

.

In effect, the picker loading runs the following pseudo-code (please note that we do NOT write this code!):

.


for (int i = 0; i < numberOfComponents; i++) {
    for (int i = 0; i < numberOfRowsInComponent; i++) {
        dataToDisplayInRow = dataFromTheDataSource;
    }
}


.

Our job is simply to answer these questions:

To answer question 1, we implement numberOfComponentsInPickerView:. Our example needs only 1, so we return 1.

To answer question 2, we implement numberOfRowsInComponent:component:.

To answer question 3, we implement titleForRow:forComponent:.

Our delegate and data source methods will provide granular answers to the questions. The following code implements these three methods. “pickerBuilder” is my name for the picker’s array data source.

.

lab2code1small

.

The other delegate method that we must implement is didSelectRow:inComponent:. This method runs whenever a new item is selected in the picker.

The method is called from the user interface, passing the arguments for the component and row selected. Our method simply does “whatever” with the row and component values.

In our situation, we go back to the data source (always the data source!) and get some data. Here’s a sample implementation.

.

lab2code2small

.

After implementing these methods, your picker should be able to display data.

.


.

.

.

Advertisements
  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: