The issue here is not the code you wrote, but the structure of the .plist file you have created. In Xcode 3, which the book was written using, when creating the .plist you are given a template that shows the root dictionary. You add keys to this dictionary - in this case arrays of strings. In Xcode 4, which it appears you used, the template does not show the root dictionary, so in order to match the book's screenshot the first inclination is to add a root dictionary. This is incorrect. The root dictionary, though not visible in the template, is actually there. So what you end up with is a .plist with a dictionary whose only object is a dictionary with a key of "Root". This dictionary contains the arrays (Games, Entertainment, Utilities) of the strings.
plist
|
Root
|
Root
/ â | â \
array____array____ array
(Games) (Entertainment) (Utilities)
Adding the lines in bold to the
-viewDidLoad method allows you to see what is going on.
Code:
} else {
//load the property list from the resource folder
NSString *pListPath = [[NSBundle mainBundle] pathForResource:@"Apps" ofType:@"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:pListPath];
//make mutable copy of the dictionary object
NSMutableDictionary *copyOfDict = [dict mutableCopy];
//get all the different categories
NSArray *categoriesArray = [[copyOfDict allKeys] sortedArrayUsingSelector:@selector(compare:)];
NSLog(@"The keys are %@",categoriesArray); // the list of keys in the root dictionary. With the current plist the only key is "Root", not the 3 array keys that were expected
//for each category
for(NSString *category in categoriesArray){
NSLog(@"The category is %@",category); // The key to be checked - again with the plist list error the only key is "Root"
//get all the app titles in that category
NSArray *titles = [dict valueForKey:category];
NSLog(@"titles is %@",titles); // the object at the key lists its contents
NSLog(@"titles is a %@", [titles class]); // You see that titles is not an array but __NSCFDictionary
//make a mutable copy of the array
NSMutableArray *mutableTitles = [titles mutableCopy];
//add new title to the category
[mutableTitles addObject:@"New App title"];
//set the array back to the dictionary object
[copyOfDict setObject:mutableTitles forKey:category];
[mutableTitles release];
}
What you end up with is the
dictionary that is the only key of the actual root dictionary being assigned to the the variable titles. So titles is not an array but a dictionary. You make the mutable copy of this and attempt to add an object. The dictionary class does not have an
addObject: method so the crash occurs.
You need to remove one dictionary layer in the plist. To make this simple and not have to retype everything, select the plist in Xcode. Select Root and open the disclosure triangle to view the keys. Select one of the keys and copy or cut it. Close the Root disclosure triangle and click in the white space below it. Paste the copied/cut key there. Repeat this for the remaining keys and then delete Root.
Hopefully this is clear. If not, I will send back your project with the amended .plist file. The issue for your question concerning Chapter 8 has the same resolution, a plist problem.
Bob