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