views:

37

answers:

4

Hello All,

So I am trying to save arrays into an NSDictionary on the fly. Let me show you the code and explain what is going on.

for (int x= 0; x <[appDelegate.people count]; x++) {
    Person *aPerson = [[Person alloc] init];
    aPerson = [appDelegate.people objectAtIndex:x];
    if ([appDelegate.groupedBusiness objectForKey:aPerson.business_name] == nil) {
        NSMutableArray *newBusiness = [[NSMutableArray alloc] init];
        //if the business does not exist in the dict, add the person to the business and add it to dict.

                    [newBusiness addObject:aPerson];

        [appDelegate.groupedBusiness setObject:newBusiness forKey:aPerson.business_name];

        [newBusiness release];
        newBusiness = nil;
        //NSLog(@"%@", appDelegate.groupedBusiness);
    } else {
        NSMutableArray *existingBusiness= [appDelegate.groupedBusiness objectForKey:aPerson.business_name];
        [existingBusiness addObject:aPerson];
                  //THIS IS THE LINE I AM NOT SURE ABOUT!!!
        [appDelegate.groupedBusiness setObject:existingBusiness forKey:aPerson.business_name];

        [existingBusiness release];
        existingBusiness = nil;
        //NSLog(@"%@", appDelegate.groupedBusiness);
    }

}

Alright, so the appDelegate has an array of "People" that has a whole bunch of attributes about a person. I am trying to set up a dictionary to sort them by their business names. I am doing this by creating an array and saving it in the dictionary with the business_name as the key. Each iteration of the loop I check to see if the key exists, if it does, pull out the existing array, add the person you are checking, and resave it to the dictionary. However, this does not appear to be happening. Is there some exotic behavior in the NSDictionary class that would prevent that? I have poured over the class web page and can't find anything. Sorry if this is a noobie question, I am still trying to understand the objective-c classes. Thanks!

+2  A: 

Why do you release existingBusiness? You are not creating an object, just taking the pointer from an array. When you invoke release, retainCount became 0 and object deallocs.

Just remove the following two lines:

[existingBusiness release];
existingBusiness = nil;

and everything should work fine.

kovpas
This was it! Thanks, I am really struggling with the memory management in this system. When do you release and when do you not?
gabaum10
You release an object which you have either sent [alloc], [copy] or [retain] to. No other.
eliego
A: 
    [appDelegate.groupedBusiness setObject:existingBusiness forKey:aPerson.business_name];

    [existingBusiness release];
    existingBusiness = nil;

This should all be removed. existingBusiness is already in the dict, and it's a mutable object - when you're adding a person to it, this will be reflected in the dictionary as well as it's the same object you're dealing with. Apart from that you have a couple of memory leaks as Daniel points out.

eliego
So the object doesn't get recreated every iteration of the loop? I want to create a new key-value pair if the person's business-name doesn't exist in the dict.
gabaum10
+2  A: 

You're way overcomplicating this, not to mention leaking a couple things.

for (Person *aPerson in appDelegate.people) {
    NSMutableArray *business = [appDelegate.groupedBusiness objectForKey:aPerson.business_name];
    if (!business) {
        business = [NSMutableArray array];
        [appDelegate.groupedBusiness setObject:business forKey:aPerson.business_name];
    }

    [business addObject:aPerson];
}
jtbandes
I don't think this is what I want to do though. I want to create a new key-value pair when the person's business_name does not exist in the dict. The thought is then I will just check against that and add the people of the same business_name to that array instead of creating new ones. I will only create a new array when the business_name does not exist in the dict.
gabaum10
@gabaum10: that's exactly what I'm doing on the 4th line.
jtbandes
Ah, ok I guess I just misinterpreted that. Either way I fixed it. Thanks for your help!
gabaum10
+1  A: 

Not an answer, but some coding style issues.

Use fast iteration if you don't need the index:

for (Person *aPerson in appDelegate.people) {

Use convenience constructors; it makes your code more readable (remember to remove the "release" at the end):

NSMutableArray *newBusiness = [NSMutableArray arrayWithObject:aPerson];

Avoid duplicate logic where possible:

NSMutableArray * business = [appDelegate.groupedBusiness objectForKey:aPerson.business_name;
if (!business) {
  business = [NSMutableArray array];
}
[business addObject:aPerson];
[appDelegate.groupedBusiness setObject:business forKey:aPerson.business_name];

The "setObject:existingBusiness" call does changes nothing apart from wasting CPU cycles, but in the case above, it makes the code somewhat more readable.

tc.
Ah it makes sense now. So when you use a mutable array, you don't have to redeclare it every iteration of the loop if that's where it is initialized? I see now. I am going to read some more on the memory management. That is what is really throwing me for a loop.
gabaum10
I'm not sure what you mean by "you don't have to redeclare it every iteration of the loop if that's where it is initialized". [NSMutableArray array] is equivalent to [[[NSMutableArray alloc] init] autorelease].
tc.