Understanding Memory management with NSDictionary release - iphone

iOS memory management is still something weird to understand to me but that's the most interesting aspect to me also, so I'm asking for some help here with my code.
I try to instantiate a NSDictionary object, I use it then I'd like to release but I got an object released error, this is the code:
if ([jsonArray count] > 0) {
NSDictionary *commentDictionary = [[NSDictionary alloc]init];
int i;
for (i = 0; i < [jsonArray count]; i++) {
commentDictionary = [jsonArray objectAtIndex:i];
NSLog(#"debugging message here"]);
commentLabel.text = [commentDictionary objectForKey:#"commentText"];
//[commentDictionary retain];
}
//[commentDictionary release];
commentDictionary = nil;
NSLog(#"NSDictionary retainCount = %d",[commentDictionary retainCount]);
}
Nothing special, I fill a dictionary from an array, in my code you can see I tried to release but than I commented out because of the error.
Why I can't release the dictionary?
Besides what's the difference between setting NSDictionary to nil that returns zero in retainCount and release (that should make the count -1)?
I thank you very much in advance for any kind of help in this topic.
Fabrizio

Do not call retainCount
retainCount is a horrible method to use for trying to figure out memory management. The absolute retain count of an object is rarely interesting and often will be unfathomable due to implementation details.
Read the documentation. It is pretty straightforward.
Now, to your code.
the alloc/init assignment to commentDictionary in your first line isn't needed and that object will be leaked on the assignment that is the first line in the for() loop.
instead of using for(;;), you could use for(commentDictionary in jsonArray) {...}
there is no reason to retain or release commentDictionary in that code; the object retrieved from the array will remain valid throughout the scope of that method.
Objective-C is a "nil eats messages" language. When you call a method on nil, that call will return 0 in almost all cases.
Oh, and what Cyril said. The static analyzer is a wonderful tool!

I advise you to run the static analyzer on that code: a lot of the mistakes that I do regarding memory management are explained by following the steps that the little blue arrows
describe.
That's a very useful/cool/forgiving tool to discover your own mistakes and understand what's happening. Build and Analyze in the build menu.
PS: retainCount is often wrong;

Related

ARC forbids autorelease?

New to ios and trying to return an NSString from an function. As I understand, I need to [NSString... alloc] init] in order to create the string for return. Also, since I called alloc, I guess I have to autorelease the object myself however I'm getting the message "ARC forbids explicit message send of 'autorelease'" so.. how do I tell ios when I'm done with that allocated NSString?
- (NSString *) generateUID
{
char foo[32];
// create buffer of all capital psuedo-random letters
for (int i = 0; i < sizeof(foo); i++)
foo[i] = (random() % 25) + 65; // 0-25 + CAPITAL_A
NSString *uid = [[NSString alloc] initWithBytes:foo length:sizeof(foo) encoding:NSASCIIStringEncoding];
NSLog (#"uid: %#", uid);
return (uid);
}
ARC = automatic reference counting = the compiler adds the necessary releases and autorelases based on its analysis of your code. You don't see this of course because it happens behind the scenes. As mentioned by sosbom in his comment, you really should read the applicable documentation on the Apple website.
You don't.
autorelease is just there for compatibilities sake, prior to iOS 5, you'd have to do:
Thing *myThing = [[Thing alloc] init]; // Retain count: 1
[myArray addObject:myThing]; // Retain count: 2
[myThing release]; // Retain count: 1
With the above code, the responsability of holding the object is given to the array, when the array gets deleted, it will release its objects.
Or in the case of autorelease.
- (MyThing*)myMethod
{
return [[[MyThing alloc] init] autorelease];
}
Then it would release the object once it gets to a NSAutoReleasePool and get removed once drained.
ARC takes care of that now, it pretty much inserts the missing pieces for you, so you don't have to worry about it, and the beauty of it, is that you get the advantages of reference counting (vs garbage collector), at the cost of an increased compile-time checking to do the ARC step, but your end users don't care about compile-time.
Add to that, that you now have strong and weak (vs their non-ARC siblings retain and assign, the later one still useful for non-retained things), and you get a nice programming experience without tracing the code with your eyes and counting the retain count on your left hand.
Short answer is you don't! ARC will handle the memory management for you.
When ARC is turned on, the compiler will insert the appropriate memory management statements such as retain and release messages.
It is best to use ARC as the compiler has a better idea of an object's life cycle and is less prone to human error.
One other important thing to note about ARC. ARC is not the same as traditional garbage collection. There is no separate process or thread running in the background, like java's GC, which deletes objects when there is no longer a reference to them. One could view ARC as compile time garbage collection :).
The only other thing to be aware of is reference cycles and bridging pointers/objects between Objective-C and Obj-C++/C. You might want to look-up http://en.wikipedia.org/wiki/Weak_reference
Hope this helps
In general, you should define a constructor method in your class and put the alloc logic in that method. Then, it is much harder to make a type casting error as the alloc/init approach always return (id) and it is not very type safe. This what built-in classes like NSString do, like [NSString stringWithString:#"foo"], for example. Here is a nice little block you can use to write code that works both with older non-arc compilation and with arc enabled.
+ (AVOfflineComposition*) aVOfflineComposition
{
AVOfflineComposition *obj = [[AVOfflineComposition alloc] init];
#if __has_feature(objc_arc)
return obj;
#else
return [obj autorelease];
#endif // objc_arc
}
You then declare the method and create an instance of the object like so:
AVOfflineComposition *obj = [AVOfflineComposition aVOfflineComposition];
Using the above approach is best, as it is type safe and the same code with with arc vs non-arc. The compiler will complain if you attempt to assign the returned object to a variable of another type.

iPhone "count" frustrations?

Okay, I know I must be missing something obvious here. Here's the sample code (which, when executed within a viewDidLoad block silently crashes... no error output to debug console).
NSMutableArray *bs = [NSMutableArray arrayWithCapacity:10];
[bs addObject:[NSNumber numberWithInteger: 2]];
NSLog(#"%#", [bs count]);
[bs release];
What am I missing?
Oh... and in case anyone is wondering, this code is just me trying to figure out why I can't get the count of an NSMutableArray that actually matters somewhere else in the program.
[mutableArray count] returns a NSUInteger. In your NSLog, you specify a %#, which requires a NSString. Obj-C does not automatically cast integers into strings, so you'll need to use:
NSLog(#"%u", [bs count]); // Uses %u specifier which means unsigned int
Bone up on how to use string formatting. Here's a link:
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html#//apple_ref/doc/uid/TP40004265-SW1
You're also releasing an object that already autoreleased. As a rule of thumb, don't ever call release/autorelease on an object, unless you yourself have also done an alloc/retain/copy on it. The majority of the time, objects you get from other class methods have already been autoreleased for you, so you shouldn't do another release.
Don't release it at the end!
arrayWithCapacity:10 returns an autoreleased object, which means it will get released automatically later. Releasing it yourself means it's count will go to -1 and unhappy things will happen! (As you have discovered)
As a general rule, objects returned by methods containing the words alloc or copy must be released by you, but no others! (Unless, of course, you retain them first)

Is release without prior retain dangerous?

I have some code which I think has extra release statements.
Is the code incorrect?
What is the end result?
I don't understand memory management well yet - even after reading lots of articles and stackoverflow answers. Thanks for straightening me out.
Update: The attached snippet works fine, but other code has the over-release problem
NSMutableArray *points = [NSMutableArray new];
for (Segment *s in currentWorkout.segments) {
[points addObjectsFromArray:[s.track locationPoints]];
}
[routeMap update:points];
[points release];
Your code is correct, but inadvisable. new acts as an implied alloc, which creates the object with a retain count of 1.
I think the last time I used new was in 1992; it's not wrong, but alloc/init is considered better practice, because it is clearer what you are doing. Please read Apple's guide to memory management, it is a comprehensive summary of the situation.
No messages can safely be sent to a deallocated object. Once an object has been released a sufficient number of times, it's deallocated. Any further messages sent to that object are going to an object that isn't there anymore. The precise result isn't completely predictable, but it usually ends in a crash. If you're less lucky, it could end in much stranger ways — for example, you could theoretically wind up with an Object A getting dealloced early and Object B allocated in the same memory location, then Object B receiving messages meant for Object A that Object B does understand but isn't supposed to receive at that time.
Basically, follow the rules. Think of it in terms of ownership. If you've claimed ownership, you need to release that ownership. If you don't own the object, you must not release it.
Take a look at this article online: http://weblog.bignerdranch.com/?p=2 .
It seems to imply that calls to release without a corresponding preior call to retain will result in a BAD_ACCESS error.
A short answer is, if you increasing the retain count of an object and you no longer are using it you should release it, otherwise you shouldnt...
So when ever you do a [objectName alloc] you are increasing the count by 1, when you use such methods as [NSString stringWithString:] these methods return an autoreleased object so you dont need to release it...if you instead did something like [[NSString stringWithString:]retain] then you are increasing the strings retain count and you should release it after you are done using it.
Im not too sure if new increases the reference count (i suspect that it would), you can always check your retain count by doing [object retainCount]... though note that even if the retain count is greater than 0, it does not mean you need to release the object, because some other class might have a reference to the object and therefore has its retain count increased by one and its the responsibility of the other class holding the reference to release it.
Hope this helps
you should use:
NSMutableArray *points = [[NSMutableArray alloc] init];
[...]
[routeMap update:points]; //if routemap stores the points, it will need it's own release retain
[points release]; //if there is a retain in the method above, reference will not be cleared
if unsure, use the build->analyze command, it will search your code for leaked references
you can get the official memory management guide from https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html

Why should a self-implemented getter retain and autorelease the returned object?

Example:
- (NSString*) title {
return [[title retain] autorelease];
}
The setter actually retained it already, right? and actually nobody should bypass the Setter... so I wonder why the getter not just returns the object? It's actually retained already. Or would this just be needed in case that in the mean time another objects gets passed to the setter?
From here http://www.macosxguru.net/article.php?story=20030713184140267
- (id)getMyInstance
{
return myInstanceVar ;
}
or
- (id)getMyInstance
{
return [[myInstanceVar retain] autorelease] ;
}
What's the difference ?
The second one allows the caller to get an instance variable of a container object, dispose of the container and continue to play with the instance variable until the next release of the current autoreleased pool, without being hurt by the release of the instance variable indirectly generated by the release of its container:
aLocalVar = [aContainer getAnInstanceVar] ;
[aContainer release];
doSomething(aLocalVar);
If the "get" is implemented in the first form, you should write:
aLocalVar = [[aContainer getAnInstanceVar] retain];
[aContainer release];
doSomething(aLocalVar);
[aLovalVar release];
The first form is a little bit more efficent in term of code execution speed.
However, if you are writing frameworks to be used by others, maybe the second version should be recommanded: it makes life a little bit easier to people using your framework: they don't have to think too much about what they are doing…;)
If you choose the first style version, state it clearly in your documentation… Whatever way you will be choosing, remember that changing from version 1 to version 2 is save for client code, when going back from version 2 to version 1 will break existing client code…
It's not just for cases where someone releases the container, since in that case it's more obvious that they should retain the object themselves. Consider this code:
NSString* newValue = #"new";
NSString* oldValue = [foo someStringValue];
[foo setSomeStringValue:newValue];
// Go on to do something with oldValue
This looks reasonable, but if neither the setter nor the getter uses autorelease the "Go on to do something" part will likely crash, because oldValue has now been deallocated (assuming nobody else had retained it). You usually want to use Technique 1 or Technique 2 from Apple's accessor method examples so code like the above will work as most people will expect.
Compare this code
return [[title retain] release]; // releases immediately
with this
return [[title retain] autorelease]; // releases at end of current run loop (or if autorelease pool is drained earlier)
The second one guarantees that a client will have a non-dealloced object to work with.
This can be useful in a situation like this (client code):
NSString *thing = [obj title];
[obj setTitle:nil]; // here you could hit retainCount 0!
NSLog(#"Length %d", [thing length]); // here thing might be dealloced already!
The retain (and use of autorelease instead of release) in your title method prevents this code from blowing up. The autoreleased object will not have its release method called until AFTER the current call stack is done executing (end of the current run loop). This gives all client code in the call stack a chance to use this object without worrying about it getting dealloc'ed.
The Important Thing To Remember: This ain't Java, Ruby or PHP. Just because you have a reference to an object in yer [sic] variable does NOT ensure that you won't get it dealloc'ed from under you. You have to retain it, but then you'd have to remember to release it. Autorelease lets you avoid this. You should always use autorelease unless you're dealing with properties or loops with many iterations (and probably not even then unless a problem occurs).
I haven't seen this pattern before, but it seems fairly pointless to me. I guess the intent is to keep the returned value safe if the client code calls "release" on the parent object. It doesn't really hurt anything, but I doubt that situation comes up all that often in well-designed libraries.
Ah, ok. from the documentation smorgan linked to, it seems this is now one of the methods that Apple is currently recommending that people use. I think I still prefer the old-school version:
- (NSString *) value
{
return myValue;
}
- (void) setValue: (NSString *) newValue
{
if (newValue != myValue)
{
[myValue autorelease]; // actually, I nearly always use 'release' here
myValue = [newValue retain];
}
}

Objective-C memory issue (iPhone)

I'm somewhat confused by the following behavior I'm seeing within an Xcode project compiled for the iPhone simulator (or device):
NSString *test = [[NSString alloc] initWithCString:"foo"];
NSLog(#"test retain count = %d", [test retainCount]); // prints 1
[test release];
NSLog(#"test retain count = %d", [test retainCount]); // also prints 1 instead of 0
However, any further attempts to access 'test' result in a crash of the Xcode enviroinment, whether it be another [test retainCount] NSLog statement or otherwise (even if only to check if test is equal to nil).
Thoughts? Compiled within a simple View based test project...code exists within project's applicationDidFinishLaunching method.
Clarification -- I know NOT to do the above in practice. This was just a test to see why in some debugging cases a retain count of 1 wasn't actually reflecting the real state of an object. Thanks for your responses. This was just a test stub to see why I was seeing certain behavior in a few cases. What I'm really trying to do is track down a very small memory leak (0.06MB) that is consistently being created whenever I destroy/recreate a custom view.
Retain counts are a debugging aid and can be misleading based on what Cocoa may be doing behind the scenes. This is particularly true with string literals where the data is permanently available and is never really deleted.
Concentrate of ensuring your code follows the Cocoa memory management rules with respect to object ownership. Where necessary, use Instruments to check for actual memory leaks.
You are calling retainCount on test after it has been released and possibly deallocated, so definitely the result is not reliable, not to mention you shouldn't be sending dealloced objects any messages.
Don't rely on retain counts...the framework may be retaining stuff on its own.
Instead, rely on the rules of memory management for objective-C. If you alloc, init, or new something, you own it and are responsible for releasing it. If you didn't, you aren't.
don't rely on the retain count; instead, make sure that you're balancing retains and releases. Here are some links on Cocoa (Touch) memory management:
http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html
When you send that release, the string is dealloced — it has no other owners retaining it. Sending further messages to it (including retainCount) is an error and won't return anything meaningful.
And as others have pointed out, don't rely on retain counts to be particularly useful. They're a piece of the picture you can look at, but they're often misleading. For example, autoreleases don't show up in the retain count, sometimes objects are retained extra times for caching purposes, etc. In this particular case, though, you're not sending the message to a valid object at all, so you're lucky to get back an answer rather than a crash.
You should read Apple's memory management guide if you're unclear on any of this. It's not too complicated and absolutely essential for programming Cocoa.
One trick to improve the code shown above would be to use the 'set to nil' convention.
EG:
NSString *test = [[NSString alloc] initWithCString:"foo"];
NSLog(#"test retain count = %d", [test retainCount]); // prints 1
[test release];
test = nil; // set to nil, as I have released the pointer, I should no longer use it.
NSLog(#"test retain count = %d, test foobarpro = %d", [test retainCount], [test foobarPro]); // will now print 0 and 0 - because any objective-c call on a nil object returns 0 (and will not crash)
By setting a pointer to zero after you release it, you future proof your code a little: Someone coming along later and editing code 10 lines below can accidentally use 'test' with likely no ill effects (or an obvious crash). I even set pointers to nil in dealloc calls, as some of the hardest debugging tasks happen when non - nil 'bad' pointers are used in destruction.
Also you can debug with zombies to look for cases where you use pointers like your invalid test.
--Tom