Read iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) Online

Authors: Aaron Hillegass,Joe Conway

Tags: #COM051370, #Big Nerd Ranch Guides, #iPhone / iPad Programming

iOS Programming: The Big Nerd Ranch Guide, 3/e (Big Nerd Ranch Guides) (14 page)

Testing your subclass

Open
main.m
. Delete the code that previously created and logged a single
BNRItem
. Then add
BNRItem
instances to the array and log them instead. Change your
main
function to look just like this:

 
#import
#import "BNRItem.h"
int main (int argc, const char * argv[])
{
    @autoreleasepool {
        NSMutableArray *items = [[NSMutableArray alloc] init];
        
BNRItem *p = [[BNRItem alloc] initWithItemName:@"Red Sofa"
                                        
valueInDollars:100
                                          
serialNumber:@"A1B2C"];
        
NSLog(@"%@", p);
    
        for (int i = 0; i < 10; i++) {
            BNRItem *p = [BNRItem randomItem];
            [items addObject:p];
        }
        for (int i = 0; i < [items count]; i++) {
            NSLog(@"%@", [items objectAtIndex:i]);
        }
    
        items = nil;
    }
    return 0;
}
 

Build and run your application and then check the output in the log navigator. All you did was replace what objects you added to the array, and the code runs perfectly fine with a different output (
Figure 2.15
). Creating this class was a success.

 

Figure 2.15  Application result

 

Check out the
#import
statements at the top of
main.m
. Why did you have to import the class header
BNRItem.h
when you didn’t you have to import, say,
NSMutableArray.h
?
NSMutableArray
comes from the Foundation framework, so it is included when you import
Foundation/Foundation.h
. On the other hand, your class exists in its own file, so you have to explicitly import it into
main.m
. Otherwise, the compiler won’t know it exists and will complain loudly.

 
Exceptions and Unrecognized Selectors

An object only responds to a message if its class implements the associated method. Objective-C is a dynamically-typed language, so it can’t always figure out at compile time (when the application is built) whether an object will respond to a message.
Xcode
will give you an error if it thinks you are sending a message to an object that won’t respond, but if it isn’t sure, it will let the application build.

 

If, for some reason (and there are many), you end up sending a message to an object that doesn’t respond, your application will throw an
exception
. Exceptions are also known as
run-time errors
because they occur once your application is running as opposed to
compile-time errors
that show up when your application is being built, or compiled. (We’ll come back to compile-time errors in
Chapter 4
.)

 

To practice dealing with exceptions, we’re going to cause one in
RandomPossessions
. In
BNRItem.h
, declare a new method:

 
@interface BNRItem : NSObject
{
    NSString *itemName;
    NSString *serialNumber;
    int valueInDollars;
    NSDate *dateCreated;
}
- (void)doSomethingWeird;
+ (id)randomItem;
 

You are going to send the message
doSomethingWeird
to an instance of
BNRItem
. The problem? You didn’t implement
doSomethingWeird
in
BNRItem.m
– you only declared it in
BNRItem.h
. Therefore,
BNRItem
does not implement
doSomethingWeird
, and an exception will be thrown. In
main.m
, send this message to a
BNRItem
.

 
for (int i = 0; i < 10; i++) {
    BNRItem *p = [BNRItem randomItem];
    
[p doSomethingWeird];
    [items addObject:p];
}

Build and run the application. Your application will compile, start running, and then halt. Check your console and find the line that looks like this:

 
2011-11-14 12:23:47.990 RandomPossessions[10288:707] ***
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
'-[BNRItem doSomethingWeird]: unrecognized selector sent to instance 0x100117280'
 

This is what an exception looks like. What exactly is it saying? First it tells us the date, time, and name of the application. You can ignore that information and focus on what comes after the

***.

That line tells us that an exception occurred and the reason.

 

The reason is the most important piece of information an exception gives you. Here the reason tells us that an
unrecognized selector
was sent to an instance. You know that selector means message. You sent a message to an object, and the object does not implement that method.

 

The type of the receiver and the name of the message are also in this output, which makes it easier to debug. An instance of
BNRItem
was sent the message
doSomethingWeird
. The
-
at the beginning tells you the receiver was an instance of
BNRItem
. A
+
would mean the class itself was the receiver.

 

Xcode
did try to warn us that something bad might happen: check the issue navigator to see the warning from the compiler that
BNRItem
has an incomplete implementation.

 

There are two important lessons to take away from this. First, always check the console if your application halts or crashes; errors that occur at runtime (exceptions) are just as important as those that occur during compiling. Second, remember that
unrecognized selector
means the message you are sending isn’t implemented by the receiver. And by remember, I mean write it down somewhere. You will make this mistake more than once, and you’ll want to be able to diagnose it quickly.

 

Some languages use try and catch blocks to handle exceptions. While Objective-C has this ability, we don’t use it very often in application code. Typically, an exception is a programmer error and should be fixed in the code instead of handled at runtime.

 

Before continuing, remove the exception-causing code: first from
main.m
...

 
for (int i = 0; i < 10; i++) {
    BNRItem *p = [BNRItem randomItem];
    
[p doSomethingWeird];
    [items addObject:p];
}

and then from
BNRItem.h
...

 
- (void)doSomethingWeird;
 
Fast Enumeration

Before Objective-C 2.0, we iterated through arrays the way you did in your
main
function:

 
for (int i = 0; i < [items count]; i++) {
    BNRItem *item = [items objectAtIndex:i];
    NSLog(@"%@", item);
}
 

Objective-C 2.0 introduced
fast enumeration
. With fast enumeration, you can write that code segment much more succinctly. Make the following change in
main.m
:

 
for (int i = 0; i < [items count]; i++) {
    
BNRItem *item = [items objectAtIndex:i];
    
NSLog(@"%@", item);
}
for (BNRItem *item in items) {
    NSLog(@"%@", item);
}
items = nil;
 

In this chapter, we have covered the basics of Objective-C. In the next chapter, we will discuss memory management in Cocoa Touch.

 
Challenges

Most chapters in this book will finish with at least one challenge that encourages you to take your work in the chapter one step further and prove to yourself what you’ve learned. We suggest that you tackle as many of these challenges as you can to cement your knowledge and move from
learning
iOS development from us to
doing
iOS development on your own.

 

Challenges come in three levels of difficulty:

 
  • Bronze challenges typically ask you to do something very similar to what you did in the chapter. These challenges reinforce what you learned in the chapter and force you to type in similar code without having it laid out in front of you. Practice makes perfect.
 
  • Silver-level challenges require you to do more digging and more thinking. You will need to use methods, classes, and properties that you haven’t seen before. But the tasks are still similar to what you did in the chapter.
 
  • Gold challenges are difficult and can take hours to complete. They require you to understand the concepts from the chapter and then do some quality thinking and problem-solving on your own. Tackling these challenges will prepare you for the real-world work of iOS development.
 

Before beginning any challenge:
always make a copy of your project directory in
Finder
and attack the challenge in that copy
. Many chapters build on previous chapters, and working on challenges in a copy of the project assures you will be able to progress through the book.

 
Bronze Challenge: Bug Finding

Create a bug in your program by asking for the eleventh item in the array. Run it and note the exception that gets thrown.

 
Silver Challenge: Another initializer

Create another initializer method for
BNRItem
. This initializer is
not
the designated initializer of
BNRItem
. It takes an
NSString
that identifies the
itemName
of the item and an
NSString
that identifies the
serialNumber
.

 
Gold Challenge: Another Class

Create a subclass of
BNRItem
named
BNRContainer
. A
BNRContainer
should have an array of
subitems
that contains instances of
BNRItem
. Printing the description of a
BNRContainer
should show you the name of the container, its value in dollars (a sum of all items in the container plus the value of the container itself), and a list of every
BNRItem
it contains. A properly-written
BNRContainer
can contain instances of
BNRContainer
. It can also report back its full value and every contained item properly.

 
Are You More Curious?

In addition to Challenges, many chapters will conclude with one or more

For the More Curious

sections. These sections offer deeper explanations of or additional information about the topics presented in the chapter. The knowledge in these sections is not absolutely essential to get you where you’re going, but we hope you’ll find it interesting and useful.

 

Other books

Gabriel's Gift by Hanif Kureishi
Impulse by Candace Camp
Heaven Is for Real: A Little Boy's Astounding Story of His Trip to Heaven and Back by Todd Burpo, Sonja Burpo, Lynn Vincent, Colton Burpo
A Guest of Honour by Nadine Gordimer
The Frozen Shroud by Martin Edwards
The Golden Day by Ursula Dubosarsky
Bandits by L M Preston