views:

105

answers:

3

I have a couple of questions regarding the code below:

(1) Is "newItem" an autoreleased object? Its getting a returned dictionary from the specified array index?

(2) Is there a simple way to access an array of dictionarys in one hit, or am I doing it the way you would expect?

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSMutableArray *menu = [[NSMutableArray alloc] init];
    NSMutableDictionary *menuItem;
    NSMutableDictionary *newItem;

    NSArray *itemName = [NSArray arrayWithObjects:
         @"Latte Medio",
         @"Cappucion Medio",
         @"Mocha Medio",
         @"Vanilla Latte Medio",nil];

    NSArray *itemFat  = [NSArray arrayWithObjects:     
         [NSNumber numberWithFloat:6.9],
         [NSNumber numberWithFloat:4.7],
         [NSNumber numberWithFloat:6.6],
         [NSNumber numberWithFloat:6.9],nil];

    NSArray *itemCals = [NSArray arrayWithObjects: 
         [NSNumber numberWithInt:516],
         [NSNumber numberWithInt:408],
         [NSNumber numberWithInt:624],
         [NSNumber numberWithInt:743],nil];

    NSLog(@"DICTARRAY ... Start");

    // Create menuItem object
    menuItem = [[NSMutableDictionary alloc] init];
    [menuItem setObject:[itemName objectAtIndex:0] forKey:@"product"];
    [menuItem setObject:[itemFat objectAtIndex:0] forKey:@"fat"];
    [menuItem setObject:[itemCals objectAtIndex:0] forKey:@"calories"];

    // Add menuItem object to menu
    [menu addObject:menuItem];
    [menuItem release], menuItem = nil;

    // Access menu to get menuItem
    newItem = [menu objectAtIndex:0];
    NSLog(@"DATA: %@",[newItem objectForKey:@"product"]);
    NSLog(@"DATA: %@",[newItem objectForKey:@"fat"]);
    NSLog(@"DATA: %@",[newItem objectForKey:@"calories"]);

    // Clean up
    [menu release], menu = nil;
    [pool drain];
    return 0;
}

gary

+7  A: 

The way you're storing this information seems odd. You're storing all the names together, all the fat together, and all the calories together, when really the items (or objects) you're dealing with are coffee drinks. It would probably be easier to make a new object, let's say CoffeeDrink, that looked something like the following:

@interface CoffeeDrink:NSObject {
    NSString *name;
    NSNumber *fat;
    NSNumber *calories;
}

@property( retain ) NSString *name;
@property( retain ) NSNumber *fat;
@property( retain ) NSNumber *calories;

@end

Then, in your code, you could have an NSArray of different CoffeeDrinks.

Jeff Kelley
thanks for the tip, I will give this a go.
fuzzygoat
This is called a model object, and it is absolutely essential to writing a full-featured Cocoa application—not just for reasons of complexity, but because some things, such as Bindings and AppleScript support, require them. For details on how to make one properly, read the Model Object Implementation Guide: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ModelObjects/
Peter Hosey
Thank you Peter, I am still learning the lanaguage and have not really looked beyond the basic data structures. I certainly will look at the object model guide, many thanks again for taking the time to post a link.
fuzzygoat
+1  A: 

newItem is not an autoreleased object, it looks to be a pointer to menuItem, which is (also) not autoreleased.

I assume you are forced to store this information as arrays for some reason or another, and you are not deliberately trying to make your life more difficult. In that sense, you can still simplify things a bit.

You could do it all in-line, but that would probably turn into "the line of code from hell". I would probably write it is like this (pseudo-code)

NSMutableDictionary* childDictionary  = // .. make the dictionary

// for each NSArray a
{
  NSString* k = // ... arbitrary key
  NSArray* a = [NSArray arrayWithObjects:// ... make the array with objects];
  [childDictionary addObject:a forKey:k];
}

// stuff it into the parent
NSDictionary* parentDictionary = [NSDictionary withObjects:childDictionary, nil forKeys:@"root"];
slf
Your right with regards menuItem is a pointer to an object in the NSMutableArray. I now realise that its not autoreleased, but will however get properly cleaned up when I release the array and all the contained objects are also destroyed.
fuzzygoat
The data structure is just a test to setup an array of dictionaries, I guess I would have been better setting up an array of custom objects, which now makes a lot more sense to be truthful.
fuzzygoat
A: 

in obj-c, the apple guidelines are, generally, when a method/object returns an object that you need to eventually release yourself, the method name will start with "new," "copy," i.e.:

newArray
copyArray

when adding things to an NSArray or NSDictionary, they'll get retained and managed by those arrays or dictionaries. the items you put in them will get a release message when you release the array or dictionary holding your items.

pxl
Thanks pxl, I now realise that I was simply creating a pointer to an existing object. So that is not an issue as the objects in the array will be release when the array goes.
fuzzygoat
> [. . .] or the name of the object, i.e.:> [. . .] arrayWithItemsThis last point is incorrect. `+arrayWithItems:` would be expected to return an autoreleased array containing the supplied items. This difference in ownership is the primary difference between `[[NSArray alloc] init]` or `[NSArray new]` and convenience methods such as `[NSArray array]`.(Also, your "i.e." should be an "e.g." since it introduces an example. Use "i.e." when you could write "that is" and "e.g." when you could write "for example". Better still, just use "that is" and "for example".)
Jeremy W. Sherman