iphone - Correct way to instantiate NSDictionary/NSArray in init without extra retains

I have numerous classes that use the various NSDictionary/NSArray collection classes as ivars but often I run into the problem of my collection class getting released before the containing class is released.

This seems to happen mostly with the collections classes and not with another model class (ie classes that I either created separately or other NS* non-collection classes).

Here are the two variations I've done and seen other people do: @implementation ClassX

// myDictionary declared as a property in the .h file as this:
// @property (nonatomic, retain) NSMutableDictionary *myDictionary;

@synthesize myDictionary;

- (id)int
    if (self = [super init])
        // Option 1:
        // If I don't instantiate and assign with 'self',
        // myDictionary ivar will not be available 
        // at times in doSomething.

        myDictionary = [NSMutableDictionary dictionary];

        // Option 2:
        // Doing this, however will keep the dictionary around.
        // because I have invoked an extra retain on the dictionary
        self.myDictionary = [NSMutableDictionary dictionary];

        // Which one is more correct?   
    return self;

- (void)doSomething
    // this will give the error about trying to invoke
    // a method on an already released instance
    [myDictionary objectForKey:@"myKey"];

- (void)dealloc
    // If I did self.myDictionary in 'init', I then
    // need to do this:
    [myDictionary release];
    [super dealloc];

So which approach is the more correct way to hold an instance of NSDictionary within a class?

2 Answers

  1. Mark- Reply


    Option 2 is correct; Option 1 is wrong.

    But you left out the best option: myDictionary = [[NSMutableDictionary alloc] init].

  2. Marks- Reply


    I recommend using

    myDictionary = [[NSMutableDictionary alloc] init];

    The memory is only within the scope of the method you're in if you call [NSMutableDictionary dictionary]. Once you leave the method, that memory goes with it which is why you need to alloc/init if you want to retain the values.

    That's why you don't have to release if you don't encounter an alloc.

    So for instance:

    - (void) doSomething {
      // Do not need to release this string
      NSString *someText = @"Hello world!";
      // You need to release this string:
      NSString *otherText = [[NSString alloc] initWithString:@"Hello world!"];
      [otherText release];

    Edited: Removed self after @mipadi @st3fan and caught my mistake. Forgot to post the change. Thanks for keeping me accountable.

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>