NSMutableDictionary Problem

Discussion in 'Mac Programming' started by larswik, Jul 17, 2011.

  1. larswik macrumors 68000

    Joined:
    Sep 8, 2006
    #1
    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
     
  2. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #2
    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?
     
  3. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #3
    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.
     
  4. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #4
    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
     
  5. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #5
    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.
     
  6. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #6
    Thanks, I will read that and then test it and report the results.

    -Lars
     
  7. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #7
    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?
     
  8. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #8
    You understand the Cocoa Memory Management Rules right? So you are aware that you are setting skills to point at an autoreleased object that you have not retained?
     
  9. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #9
    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
     
  10. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #10
    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.
     
  11. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #11
    I kind of see what you are saying. So I need to instantiate the dictionary myself.

    -Lars
     
  12. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #12
    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.
     
  13. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #13
    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?
     
  14. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #14
    If your AppController creates it then it should release it in it's dealloc method.
     
  15. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #15
    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.
     
  16. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #16
    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.
     
  17. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #17
    And that answered all my questions and cleared up some gray area with memory management.

    Thanks you very much for your help Rob.
     

Share This Page