iPhone "count" frustrations? - iphone

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)

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.

Correct use of autorelease

I am trying to understand why my application crashes and I am going through my code. I am pretty sure that this is a valid use of autorelease:
(part of the code)
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSMutableArray *ids = [[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
return [NSArray arrayWithArray:ids];
}
Is this valid? The NSArray arrayWithArray returns an autorelease object doesn't it? I also have some difficulties in understanding the scope of autoreleased objects. Would the autoreleased object (if it is in this case) be retained by the pool through out the method that invoked the method that this code is a part of?
- (void)codeThatInvokesTheCodeAbove {
NSArray *array = [self.dao allQuestionsFromCategories];
...
}
Would the array returned be valid in the whole codeThatInvokesTheCodeAbove method without retaining it? And if it was, would it be valid even longer?
Got some issues understanding the scope of it, and when I should retain an autorelease object.
That is valid, but -- really -- you can just skip the [NSArray arrayWithArray:ids]; entirely as there is no need to create a new array.
An autoreleased object is valid until the autorelease pool is drained, which typically happens once per pass through a run loop (or "periodically, but never while your block is executing" when enqueuing stuff via GCD).
The documentation explains it all better than I.
There is no need to create an immutable array because the return will effectively "up cast" the NSMutableArray to NSArray. While this is meaningless at run time, it means that the caller cannot compile a call to a mutating method of the returned value without using a cast to avoid the warning. Casting to avoid warnings in this context is the epitome of evil and no competent developer would do that.
If it were an instance variable being returned then, yes, creating an immutable copy is critical to avoid subsequent mutations "escaping" unexpectedly.
Have you read the memory management documentation? Specifically, the part about autorelease pools? It makes it quite clear how autorelease works. I hate to paraphrase a definitive work.
[NSArray arrayWithArray:] returns an autoreleased object. If you want codeThatInvokesTheCodeAbove to take ownership of the array, you should call retain on it (and rename codeThatInvokesTheCodeAbove according to apple's guidelines). Otherwise, if you don't care that ownership of the object is ambiguous then your code is okay.
In other words, [NSArray arrayWithArray:] returns an array that you don't own, but you have access to it for at least this run cycle. Therefore, codeThatInvokesTheCodeAbove will have access to it for at least this run cycle. Ownership is not clear, since nobody called alloc, copy, new, or mutableCopy or retain. It is implied that NSArray called autorelease before returning the new array, thus relinquishing ownership.
My information comes from http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH.
So, to answer your question, yes your posted code is valid. Whether it's correct depends on what it is you are trying to accomplish.
Autoreleased object are objects that are marked as to be release later.
There is a very particular object that is automatically created by UIApplicationMain: an UIRunLoop.
Imagine it like a while structure, it cycle until application is terminate, it receives every event and properly resend it to your interested classes, for example. Just before UIApplicationMain there is a command to create an NSAutoreleasePool that, once the NSRunLoop is ready, attach to it. When you send an -autorelease command to an object, the NSAutoreleasePool will remember to release it when is released itself. It's dangerous to use it many times in platforms that has less memory (iOS devices), because objects aren't released when you send an -autorelease command but when the NSAutoreleasePool is drained (when app releases it).
If you want to free the non-mutable list before you return, you can use something like this:
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSArray* result;
NSMutableArray *ids = [[NSMutableArray alloc] init]; // AUTORELEASE REMOVED FROM HERE
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
result = [NSArray arrayWithArray:ids]; // COPY LIST BEFORE IT IS FREED.
[ids release]; // MUTABLE LIST FREES _NOW_
return result; // NONMUTABLE COPY IS RETURNED
}
It is not worth doing this unless your mutable array is likely to sometimes use a lot of memory.

iPhone object checking to release

I want to check if an object has some count or not Here is my testing code
NSMutableArray *array=[[NSMutableArray alloc]init];
if(array)
{
NSLog(#"hiiiiiii");
}
CASE-2
NSMutableArray *array=[[NSMutableArray alloc]init];
[array release];
if(array)
{
NSLog(#"hiiiiiii");
}
Here in both cases i got same output as printed "hiiiiiii".
Can anyone tell me how will i check if my object need to release or already released.
I know that i should have track of my object's counters but i am at a stage where my code is too much complexed and i need help..
Please help..
ALso tell that how much memory leak is allowed by apple?
There is no way to check if you "should" release an object. Doing something like "if(object)" only checks the pointer to the object. It will return true even if the object it was pointing to was destroyed a long time ago. This is what happens in your second case. The object is destroyed when you call release, but the pointer is still pointing at something, so it returns true. It will only return false if the pointer is set to nil.
However, there is a simple set of rules for calling release. If you ever call "alloc", "new", "copy", "mutableCopy" or "retain" on object, you must always call "release" or "autorelease" on it. That will prevent any memory leaks.
Apple does not have a publicized amount of memory leaks allowed. It is always safest to eliminate any known memory leaks; plus, it will mean better performance for your customers.
In your second case you are releasing the NSMutableArray but still it store a non zero value although it's no longer for use (To call function OR fetch value).That the reason your if condition got true.
Just remember whenever you call release on any object, Do'nt forget to assign nil to that, So your second code should look like below.
CASE-2
NSMutableArray *array=[[NSMutableArray alloc]init];
[array release];
array = nil;
if(array)
{
NSLog(#"hiiiiiii");
}
There is a simple rule of memory management in Object-C if your alloced or retain any object you must call release on that,
Read memory management Guide from Apple.

Understanding Memory management with NSDictionary release

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;

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];
}
}