3

I'm developing an iPhone application and I've just created this method (it's in a singleton class):

- (NSDictionary *)getLastPosts
{
    SBJsonParser *parser = [[SBJsonParser alloc] init];

    NSURLRequest *request = [NSURLRequest requestWithURL:
                             [NSURL URLWithString:http://example.org/last/]];

    NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

    NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];

    NSDictionary *data_dict = [parser objectWithString:json_string error:nil];

    // release stuff
    [parser release];
    [request release];
    [response release];
    [json_string release];

    return data_dict;
}

I'm a newbie obj-c developer so I'm not sure of this two things:

  • Is it correct the four vars release in the method's end?
  • When should I release the NSDictionary data_dict?

UPDATE 1

If data_dict was NSDictionary *data_dict = [[NSDictionary alloc] init] when I'll should release it?

UPDATE 2

enter image description here

In the caller I have this:

- (void)callerMethod
{
    NSDictionary *tmpDict = [mySingleton getLastPosts];
    NSLog(@"retain count: %d", [tmpDict retainCount]);
}

and the debug console prints:

retain count: 2
  • Why "Xcode Analyze" says me these lines?
  • And why the retain count it's 2?
Fred Collins
  • 5,004
  • 14
  • 62
  • 111
  • You are returning the `data_dict` to another method, so you cannot release it in this method. You should `autorelease` it, so the receiving method still has the data. With the method you used, it is already autoreleased. – Mundi Aug 14 '11 at 19:40
  • 1
    if data_dict is obtained with `[[NSDictionary alloc] init]` it will have retain count 1 and you will need to autorelease it later. If it is obtained with `[parser objectWithString:json_string error:nil];` it is already autoreleased and you should return it withouth autoreleasing it. – doppioslash Aug 14 '11 at 20:50
  • Oh yes, right. It was a mistake :) It has retain count of 2 because the first owner is the singleton's method and the other owner is caller in the view controller? – Fred Collins Aug 14 '11 at 20:56
  • I think the `retainCount` method can't really be trusted, the static analyzer should be more trustworthy. As far as I know the dictionary is returned from `getLastPosts` with a retain count of 1 but a 'virtual' (my definition) retain count of 0 as autorelease has already been called on it and at some point the pool will release it. To have a retain count of 2 at that point you should call retain on `tmpDict`. – doppioslash Aug 14 '11 at 21:02
  • 1
    http://stackoverflow.com/questions/2640568/how-to-get-the-reference-count-of-an-nsobject explains why retainCount can't be relied on. – doppioslash Aug 14 '11 at 21:03

3 Answers3

6

In general, it is good to release objects you do not need any more. But remember - Only things that have alloc, new or copy in their initialization need to be released. Otherwise they are already autoreleased.

So, it is ok to release the parser, not ok to release the request, not ok to release the response, ok to release the json_string.

Mundi
  • 79,884
  • 17
  • 117
  • 140
  • you just forgot to add that the `data_dict` is `autorelease` and should not be released inside this scope, as it will be released later by the nsautoreleasepool – Felipe Sabino Aug 14 '11 at 19:29
4
SBJsonParser *parser = [[SBJsonParser alloc] init];

You called init, then you own the instance and you need to release it.

NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:http://example.org/last/]];

You called a class method that returns an autoreleased instance which will be added to the autorelease poll.

NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

Autoreleased.

NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];

You called init, you will need to release it.

NSDictionary *data_dict = [parser objectWithString:json_string error:nil];

Returned instance, autoreleased.

Thus you just need to release two of them:

[parser release];
[json_string release];

if NSDictionary *data_dict = [[NSDictionary alloc] init] then you would need to autorelease it yourself: the convention is that any instance returned by a method is autoreleased.

By the way by autoreleasing it you make sure that it will be available until the autorelease pool is emptied (unless you call release on it).

To autorelease it:

return [data_dict autorelease];
doppioslash
  • 1,276
  • 11
  • 14
  • Thanks for the explanation. It will be possible the autorelease pool will drained before I use my var? – Fred Collins Aug 14 '11 at 19:45
  • 1
    The autorelease pool is drained when the event that created it ends, so it shouldn't. Autorelease will surely keep your object around for you to have the chance to retain it from the code that needs it. For more practical information about autorelease pools see this series of youtube videos: http://www.youtube.com/watch?v=59bDaCydrH4&feature=related – doppioslash Aug 14 '11 at 19:48
  • 1
    Every init needs a release or the instance will leak, when you get an autoreleased object from a method the release is a time-bomb: it won't happen instantly as with release. A delayed release. You should still call retain on the instance when you want to keep it around, and then call release when you're finished with it. It won't be deallocated instantly, it still has retain count 1. When the autorelease pool is emptied it will call release on the instance bringing the retain count to 0 and causing it to be deallocated. – doppioslash Aug 14 '11 at 19:54
  • Thank you very much doppioslash (is an italian username?). Have a nice day. – Fred Collins Aug 14 '11 at 20:09
  • Yes it is! Doppio means double. You're very welcome, happy coding! :) – doppioslash Aug 14 '11 at 20:28
  • I'm italian too :) Now I've a strange problem with this code. Check my update! – Fred Collins Aug 14 '11 at 20:37
  • Your name sounded american, you fooled me! :D if `data_dict` is obtained with `[[NSDictionary alloc] init]` it will have retain count 1 and you will need to autorelease it later. If it is obtained with `[parser objectWithString:json_string error:nil];` it is already autoreleased and you should return it withouth autoreleasing it: `return data_dict;` – doppioslash Aug 14 '11 at 20:57
  • @doppioslash let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/2470/discussion-between-fred-collins-and-doppioslash) – Fred Collins Aug 14 '11 at 20:59
  • It is actually the `alloc` that implies the +1 retain count; `init` effectively preserves that +1 throughout it's implementation (which is why you might see `[self release]; self = [[Something somewhere] retain];` and it is perfectly valid. – bbum Aug 14 '11 at 23:55
2

It is correct to release parser and json_string because these are created with methods containing "alloc". It is incorrect to release the others because they are autoreleased.

You never have to release data_dict in this method, since it is autoreleased.

Please read the Objective-C memory management rules.

Chuck
  • 234,037
  • 30
  • 302
  • 389
Enchilada
  • 3,859
  • 1
  • 36
  • 69