Mac NSMutableDictionary Problem

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
Hi, I have 2 NSTextFields for data entry, an NSButton and NSPopUpButton.

When the button is pressed the 2 NSTextFields are entered into an NSMutableDictionary as the 'object' and 'key'. Also the NSTextField for the 'key' is also added to the NSPopUpButton.

The goal is the user can enter their own items, the 'KEY' like a Sword and then '25' in the second NSTextField. Later the user can use the NSPopUpButton to select the item 'Sword' and in an NSTextField, called bonus, the number '25' is displayed as a string.

All my code works for the NSPopUpButton, but I don't think I am populating the NSMutableDictionary correctly. I know the Dictionary needs to have a 'nil' that defines the end of it but the mutableDictionary starts with no entries until the user adds them. I think that is my problem area.

@interface
Code:
NSMutableDictionary *skills;
@implementation
Code:
- (IBAction)addSkillPrefButton:(id)sender {
    [popUpButtonDisplay addItemWithTitle: [skillNamePref stringValue]]; // adds item to popUp
    [skills setObject:[skillBonusPrefField stringValue] forKey:[skillNamePref stringValue]]; // adds obj and key to Dict.
    [skillNamePref setStringValue:@"-"]; //resets textfield
    [skillBonusPrefField setStringValue:@"-"]; //resets textfield
}
I have been scratching my head for a while.

Thanks,

-Lars
 

jiminaus

macrumors 65816
Dec 16, 2010
1,449
0
Sydney
Is skills itself still nil when addSkillPrefButton: executes? Add an NSLog to find out. If it is, think about where and how to initialise it?
 

robbieduncan

Moderator emeritus
Jul 24, 2002
24,759
133
Harrogate
I know the Dictionary needs to have a 'nil' that defines the end of it but the mutableDictionary starts with no entries until the user adds them. I think that is my problem area.
This is simply not true. nil is required to mark the end of the list when using dictionaryWithObjectsAndKeys: but this is for this method only. It, in now way, implies that this is a general property of the dictionary.
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
It's a Cocoa Application. I thought of using NSLog to see what was put into the dictionary but I had no idea how to check that since it is not a console based program. Can I use the console and a cocoa app at the same time to check this?

-Lars
 

robbieduncan

Moderator emeritus
Jul 24, 2002
24,759
133
Harrogate
It's a Cocoa Application. I thought of using NSLog to see what was put into the dictionary but I had no idea how to check that since it is not a console based program. Can I use the console and a cocoa app at the same time to check this?

-Lars
NSLog will write to the XCode console log or the System console (see Console.app in /Applications/Utilities) so yes, it can be used with a GUI Cocoa app.
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
Thanks, I will read that and then test it and report the results.

-Lars
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
I add this to my Method 'AwakeFromNib' last night and today.
Code:
    skills = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"Items", @"Enter Item", nil];
    [popUpButtonDisplay addItemWithTitle: [skills objectForKey: @"Enter Item" ]];
    
    if ([skills objectForKey:@"Enter Item"] == nil) {
        NSLog(@"it is nill - awake");
    }
    else{
        NSLog(@"It is there - awake");
    }
I have a button attached to a method and I used // to hide all the code except for the same IF statement to verify the NSMutableDictionary is still holding the same Object and Key. I got the second and third response back in the console.app. So it sees it when it creates it but then seems to go away?

Code:
2011-07-17 12:41:17.777 Xp Calc2[821:903] It is there - awake
2011-07-17 12:41:31.636 Xp Calc2[821:903] -[NSCFString objectForKey:]: unrecognized selector sent to instance 0x516270
2011-07-17 12:41:31.636 Xp Calc2[821:903] -[NSCFString objectForKey:]: unrecognized selector sent to instance 0x516270
Here is the code for the button as I was testing it
Code:
- (IBAction)addSkillPrefButton:(id)sender {
   // [popUpButtonDisplay addItemWithTitle: [skillNamePref stringValue]]; // adds item to popUp
   // [skills setObject:[skillBonusPrefField stringValue] forKey:[skillNamePref stringValue]]; // adds obj and key to Dict.
   // [skillNamePref setStringValue:@"-"]; //resets textfield
   // [skillBonusPrefField setStringValue:@"-"]; //resets textfield
    if ([skills objectForKey:@"Enter Item"] == nil) {
        NSLog(@"it is nill");
    }
    else{
        NSLog(@"It is there");
    }
}
My guess is that the Dictionary is gone or at least the items in it? Perhaps I need to instantiate it myself with the alloc and init?
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
I have read the Memory Management and MOST of it I understand. I remember the NARC approach to memory management. I take ownership of the object when I select New, Alloc, Retain and Copy (NARC) and need to release it myself when I use one of those.

I followed a couple examples I saw online and on a Lynda.com tutorial, and they did not retain the NSMutableDictionary. If I do not retain, then I am at the mercy of the program to decided when it is done with it or the retain count is 0 and it gets rid of it.

1) I thought if I added a Object and Key to the Dictionary that it would automatically retain until I remove the items or quit the program? Which is why I did not think I needed to alloc and init the dict.

2) If I do need to retain then in my interface I say NSMutableDictionary * skills; Then in my Implementation of the AppController class, in the method AwakeFromNib I would then have skill = [[NSMutableDictionary alloc] init]; I would then take ownership of the Dictionary.

3) Can I then start with an empty NSMutableDictionary and then just use 'skill setObject: forKey:' to populate the dictionary? Or when I instantiate it in the 'AwakeFromNib' must I make sure I have at least 1 Object and Key with the following nil at the end, just a nil or it is OK to leave empty?

4) When I release the dictionary at the end when I quit the program, where do I do that? Do I do it back in Main.m even thought almost all the code is written in the AppController.m class?

So I have a pretty good understanding of Memory management. Doing these little programs help me better understand it, and how to use it. The Good news is I can see what the problem is by the error messages, and your guys help of course. But there is some gray area in my understanding as I listed above in 1-4.

Thanks!

-Lars
 

robbieduncan

Moderator emeritus
Jul 24, 2002
24,759
133
Harrogate
I am not talking about the keys and values. I'm talking about the dictionary itself. It (the dictionary) is autoreleased.

To be 100% clear:
Code:
skills = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"Items", @"Enter Item", nil];
The dictionary is autoreleased. At some point in the near future (at the end of the current runloop iteration) skills will be nil.
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
I kind of see what you are saying. So I need to instantiate the dictionary myself.

-Lars
 

robbieduncan

Moderator emeritus
Jul 24, 2002
24,759
133
Harrogate
I kind of see what you are saying. So I need to instantiate the dictionary myself.

-Lars
You could just retain that one. Whether you are creating it in the right place (I'd normally expect to see it created when the object is created) is up to you.
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
Problem is fixed. I added the 'skills = [[NSMutableDictionary alloc] init];' so I took ownership of the Dictionary. I need it until the program quits. Since Instantiated the AppControllor class should I release it there?

I need it released when the program exits but I don't know the best place to place my [skills release]; in main.m, dealloc method or other?
 

robbieduncan

Moderator emeritus
Jul 24, 2002
24,759
133
Harrogate
Problem is fixed. I added the 'skills = [[NSMutableDictionary alloc] init];' so I took ownership of the Dictionary. I need it until the program quits. Since Instantiated the AppControllor class should I release it there?

I need it released when the program exits but I don't know the best place to place my [skills release]; in main.m, dealloc method or other?
If your AppController creates it then it should release it in it's dealloc method.
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
That I makes sense. Is the dealloc method called automatically at the very end when the application quits, or must I send it a message?

My gut feeling is that when you select Quit or COMMAND + Q it automatically sends a message to the dealloc method.
 

robbieduncan

Moderator emeritus
Jul 24, 2002
24,759
133
Harrogate
That I makes sense. Is the dealloc method called automatically at the very end when the application quits, or must I send it a message?

My gut feeling is that when you select Quit or COMMAND + Q it automatically sends a message to the dealloc method.
You should never call dealloc (on any object). It is called automatically when the object is cleaned up from memory. Note that when your application quits all it's memory gets handed back to the OS so you don't actually have to worry about this specific case too much.
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
And that answered all my questions and cleared up some gray area with memory management.

Thanks you very much for your help Rob.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.