I have the following function, which results in *timeString leaking memory. I am fairly new to Objective-C (and memory management), but I read that you only need to release objects that you alloc in the first place. Because I alloc *formatter, and then set that to *timeString, does this mean that I now have to release *timeString too?
Here's the code:
-(NSString *)getDate{
NSLog(#"getDate");
NSDateFormatter *formatter;
NSString *timeString;
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd"];
timeString = [formatter stringFromDate:[NSDate date]];
[formatter release];
return timeString;
}
EDIT: Here is where the getDate function is called:
-(NSString *)getFileName{
//nameofXMLFile = page_##
NSString *nameOfFile = [NSString stringWithString:pageTitle];
//nameOfXMLFile = page_##.DataCheckSheet.xml
nameOfFile = [nameOfFile stringByAppendingString: #".DataCheckSheet.xml"];
NSString *dateString = [self getDate];
dateString = [dateString stringByAppendingString: #"_"];
NSLog(#"datestring: %#", dateString);
dateString = [dateString stringByAppendingString:nameOfFile];
NSLog(#"datestring with append: %#", dateString);
//nameOfXMLFile = yyyy-MM-dd_page_##.DataCheckSheet.xml
nameOfFile = dateString;
return nameOfFile;
}
As you already correctly stated, all objects, that aren't explicitly alloced, are per definition 'autoreleased', which means they will be destroyed, once they leave the scope of the function that defined them.
To keep an object valid longer than that, for example, by keeping it around as a class object, you would call 'retain' on it.
This 'retain' needs to 'released', just like an 'alloced' object.
By passing the reference to the object in question as return value, the scope of the object gets expanded to the function, which called the function in the first place...which means, the object would be destroyed at the end of the calling function, unless it is retained by then.
nameOfFile is still that very object in question, since you copied the address of dateString to that variable, effectively erasing that string from existence (it will thereby get autoreleased).
Try to avoid such assignments, unless you have a reason for them, to avoid confusion.
In short: If you have a chain of function calls and returns, make sure, that there isn't a 'retain' somewhere along the line, which doesn't get released appropriately, and you'll be fine.
Your best bet to understand leaks is to use Instruments and its "Leaks" template.
The "leak" instrument will show you what objects are leaked and you will be able to jump right away to the ObjectAlloc instrument to see retain/releases calls to the leaked object. You should then be able to find where missing release(s) are.
As is, your code looks OK wrt memory management. However most of the strings created here are autoreleased, which means they will be effectively released when the outter autorelease pool will be drained. Until the pool is drained, your object might appear to leak.
In typical applications, the main thread has an autorelease pool automatically installed by NSApplication/UIApplication, yet the pool is drained only when the application receives events (see this question)
In a usual detached thread (using NSThread or pthread), you have to install your own pool(s) (and drain them regularly).
GCD dispatch queues install their own autorelease pool and drain them from time to time.
Related
Here we have some examples from About Memory Management
In the first example
- (NSString *) fullName {
NSString *string = [[[NSString alloc] initWithFormat:#"%# %#", self.firstName, self.lastName] autorelease];
return string;
}
In this example is how the above method is called
{
Person *aPerson = [[Person alloc] init];
NSString *name = aPerson.fullName;
[aPerson release];
}
So I assume that the *name is autoreleased after code flow reaches the closing curly braces.
Is that true?
And in general autorelease of an object, depends on the scope and lifetime of the variable which references that object.
Are there any criteria which manage the autorelease pool of objects in a Objective-C program?
Thanks.
Release of an autoreleased object takes place when the autorelease pool which the object has been pushed to by autorelease is released/drained explicitly, provided that the object's retain count at that moment is 0+ (that is, nobody else but the autorelease pool is retaining it).
An object is not getting autoreleased just because it has gone out of scope. In your example we can only say for sure that it won't get released before the closing curly brace, but as H2CO3 said, without the relevant source code we cannot predict when it is actually cleaned up. In Cocoa (Touch) apps, threads with runloops have a loop-level autorelease pool which they drain at the end of each runloop iteration. If your method is called from the runloop (e.g. as part of an event handler callback), autoreleased objects will be released shortly after the handler code returns; otherwise there is no such guarantee.
Note that the above holds for non-ARC environment; others may confirm whether it's still valid or not when using ARC.
Using ARC, is it now OK to assign a string value like this:
self.userName = [[NSString alloc] initWithString:self.currentParsedCharacterData];
Or does that still cause a memory leak, thus requiring me to assign it like this:
NSString *tmpString = [[NSString alloc] initWithString:self.currentParsedCharacterData];
self.userName = tmpString;
The first snippet is just fine under ARC, and is the better of the two ways. Apple has an example like this in the Transitioning to ARC guide:
- (void)contrived {
Person *aPerson = [[Person alloc] init];
[aPerson setFirstName:#"William"];
[aPerson setLastName:#"Dudney"];
[aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];
NSLog(#"aPerson: %#", aPerson);
}
and says:
ARC takes care of memory management so that neither the Person nor the NSNumber objects are leaked.
The setYearOfBirth: message with an alloced NSNumber corresponds to your snippet.
The compiler understands that, in the first case, aPerson is going out of scope and needs to be released before that happens, and, in the second case, that there is no explicit reference to the NSNumber object and that it must be either released or put into the autorelease pool. It takes care of both these requirements on your behalf.
Yes, with ARC it is ok. In fact, I would recommend the first way you have it implemented.
Either of your examples is fine. There is no difference between the two as far as memory management/ARC goes.
If I have a piece of code that looks like this:
- (void)testSomething
{
__weak NSString *str = [[NSString alloc] initWithFormat:#"%#", [NSDate date]];
NSLog(#"%#", str);
}
the output will be (null) because there are no strong references to str and it will be immediately released after I allocate it. This makes sense and is spelled out in the Transitioning to ARC guide.
If my code looks like this:
- (void)testSomething
{
__weak NSString *str = [NSString stringWithFormat:#"%#", [NSDate date]];
NSLog(#"%#", str);
}
then it correctly prints out the current date. Obviously you would expect it to work in a non-ARC world, since str would be autoreleased and therefore valid until this method exits. However, in ARC-enabled code people generally consider the two forms (stringWithFormat & alloc/initWithFormat) to be equivalent.
So my question is whether code like the second example is guaranteed to work under ARC. That is, if I have a weak reference to an object that I get via what we would normally consider an autoreleasing convenience constructor, is it guaranteed to be safe to use that reference in the same scope I normally would have without ARC (i.e. until the method exits)?
The conventions of autoreleasing and allocing still apply in the world of ARC. The only difference is that ARC will insert extra retain/release calls to make it much harder to leak objects or access a dealloced object.
In this code:
__weak NSString *str = [[NSString alloc] initWithFormat:#"%#", [NSDate date]];
The only place the object is retained (or equivalent) is the alloc. ARC will automatically insert a release command, causing it to be immediately dealloced.
Meanwhile, in this code:
__weak NSString *str = [NSString stringWithFormat:#"%#", [NSDate date]];
By convention, the return value of a convenience constructor like this must be an autoreleased object*. That means the current autoreleasepool has retained the object and will not release it until the pool is drained. You are therefore all but guaranteed that this object will exist for at least the duration of your method - although you probably shouldn't rely on this behaviour.
(* or retained in some other way)
The lifetime of a local weak variable is not guaranteed at all. If the object that the variable points to is deallocated, the weak variable will point to nil afterwards.
If you have a weak reference to an object that you got via a method that does not return a retained object, it is not safe to assume that this object lives until the method exits. If you want to make sure that the object survives, use a strong reference.
Here is an example that shows that a non-retaining method's return value is not guaranteed to end up in the autorelease pool:
Create a new iOS project (Single View App using ARC and Storyboards)
Add this method to the AppDelegate.m:
+ (id)anObject
{
return [[NSObject alloc] init];
}
Replace -application:didFinishLaunchingWithOptions::
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__weak id x = [AppDelegate anObject];
NSLog(#"%#", x);
return YES;
}
Important: Now set the Optimization level for Debug to -Os.
In this example, +[AppDelegate anObject] acts like a convenience constructor, but you will see (null) logged if you execute it on a device with -Os optimization. The reason for that is a nifty ARC optimization that prevents the overhead of adding the object to the autorelease pool.
You may have noticed that I switched to not using a library method like +[NSString stringWithFormat:]. These seem to always put objects in the autorelease pool, that may be for compatibility reasons.
after having spent few months in trying to master the syntax and rules, I am going deeper in memory management rules.
One thing I do not understand and causing me confusion is how one creates objects.
Based on what stated in apple memory management guide, the following is a valid approach:
– (NSArray *)sprockets {
NSArray *array = [NSArray arrayWithObjects:mainSprocket,auxiliarySprocket, nil];
return array;
}
because I am not causing any memory leaks.
The reason why is that it's not using alloc for creating array and therefore sprockets is not the owner.
However I am wondering now what's inside arrayWithObjects.
Because it happens that in my apps I often have factory for creating custom objects using something similiar to:
return [[MyObject alloc] initWithParameter:(id)params]; // possible leak
If I want to change with a static method like:
return [MyObject initWithParameter:(id)params];
what could be in initWithParameter for adhere to memory rules ? And what if MyObject extends some other object ? I also find out that method naming rules are important to properly advise programmer, what are this rule ?
Also could you point out a web link where this is explained (I am not yet good in finding docs on apple web site).
thanks
This is the page you're looking for: Memory Management Rules. It all comes down to adhering to the rules of ownership for an object.
If you create an object using alloc then you own that object and must release it. For example:
NSString* str = [[NSString alloc] init];
//do something with your str object
[str release];
str = nil; //don't forget to set it to nil, it's still
//pointing to the (now unallocated) block of memory
If you create an object using a factory method, for example:
NSString* str = [NSString stringWithString:#"blah"];
Then what is happening here is that it is creating the string object using alloc for you and then returning the object but first adding it to the local autorelease pool. To use the example in your question.
return [[MyObject alloc] initWithParameter:(id)params]; // possible leak
return [[[MyObject alloc] initWithParameter:(id)params] autorelease]; //now autoreleased -- no leak
Here is the page on Autorelease Pools. Apple say it better than me.
An autorelease pool is an instance of NSAutoreleasePool that “contains” other objects that have received an autorelease message; when the autorelease pool is deallocated it sends a release message to each of those objects. An object can be put into an autorelease pool several times, and receives a release message for each time it was put into the pool. Thus, sending autorelease instead of release to an object extends the lifetime of that object at least until the pool itself is released (the object may survive longer if it is retained in the interim).
Method naming rules are important as it gives a strong indication as to whether the method returns an autoreleased object. In this example I would name the method:
[MyObject myObjectWithParameter:(id)param]
Hope this has helped.
It is standard practice for alloc and creation methods to return a retained object. Anything that starts with init, create, or the object name will clue other programmers into the purpose of the method.
Even if you create with alloc, if the purpose of your method is to pass on ownership, you should not release the object.
Ok, I know the answer to this question should be obvious, but I need a little push in the right direction.
I find myself writing a fair number of methods that follow the following pattern:
-(NSThing*)myMethod{
NSThing *thing = [[NSthing alloc] init];
// do some stuff with the thing
return thing;
}
My question is, how do I handle the release of this object? Clearly I can't release it within the method.
usually you would autorelease it
-(NSThing*)myMethod{
NSThing *thing = [[NSthing alloc] init];
// do some stuff with the thing
return [thing autorelease];
}
Autoreleasing is the easy way to get out of this, as newacct said. However, you should take into consideration the "ownership" of the object you're returning.
In Objective-C, the general rule of thumb is that any method with alloc, new, or copy in its name returns an object that is not autoreleased, while other methods (like class methods) pre-autorelease the object to be returned. So these three are not equivalent in terms of autorelease (although the compiler may do some magic and reduce them all to string constants anyway):
// Autoreleased
NSString *string1 = [NSString stringWithString:#"aString"];
NSString *string2 = [[[NSString alloc] initWithString:#"aString"] autorelease];
// NOT autoreleased
NSString *string3 = [[NSString alloc] initWithString:#"aString"];
Your code can take a similar approach, where you consider who owns the object you're returning. In the specific example you provided, the method is the one allocing and initing the object, so in general you're responsible for autoreleaseing [sic] it within your own method. However, if you were to write a method that takes a preexisting object and modifies it in some way, you would not own that object and would not be responsible for autoreleasing the returned object. (Doing so could actually cause problems down the road when the autorelease pool to which the object belongs gets drained.)
See also (thanks to Peter and Quinn in the comments!):
Memory Management Rules