I am just reading through the Practical Memory Management guide.
I am somewhat confused by this block of code:
- (void)printHello {
NSString *string;
string = [NSString stringWithFormat:#"Hello"];
NSLog(#"%#", string);
}
It seems to me that string is going to have a reference count of 0. Is this true?
What stops string from being deallocated before we call NSLog(string)?
Is this somehow equivalent to this:
- (void)printHello {
NSString *string;
string = [[[NSString stringWithFormat:#"Hello"] retain] autorelease];
NSLog(#"%#", string);
}
Edit: Similarly this code is given in the Practical Memory Management
guide:
- (NSString *)fullName {
NSString *string = [NSString stringWithFormat:#"%# %#", firstName, lastName];
return string;
}
When and how does the return value get freed? Who is the owner? Does the caller of fullName need to release the string returned by full name?
Strictly speaking,
- (void)printHello {
NSString *string;
string = [NSString stringWithFormat:#"Hello"];
NSLog(#"%#", string);
}
Is not equivalent to
- (void)printHello {
NSString *string;
string = [[[NSString stringWithFormat:#"Hello"] retain] autorelease];
NSLog(#"%#", string);
}
The convention is that a method should autorelease any object it returns. The only exception (AFAIK) is for constructors, which return an object with a +1 retain count. Since [NSString stringWithFormat:] returns an object. In first snippet, stringWithFormat: returns an already autoreleased object. the second snippet, you're retaining it once more and it'll be released twice (which has the same effect, but the second retain/autorelease pair is redundant).
Ok, now to answer your question. Essentially, every time UIKit calls your code, it creates an NSAutoreleasePool object. Every time you autorelease an object, its added to this pool. Finally, when your code returns back to UIKit, it calls the drain method on the pool (i.e [pool drain]) and that releases every object which has been added to the pool and deallocates the pool. Also, autorelease pools can be nested, so you can create your own pools and drain them if you're going to be creating a lot of autoreleased objects. It isn't as complicated as it sounds.
I'd highly recommend that you read the Autorelease Pools chapter in the Memory Management Guide (Which incidentally, comes right after the Practical Memory Management chapter).
First of all:
NSLog(string);
Don’t do this. (I just realized it comes right from the Apple docs. Weird.) The first argument to NSLog is the formatting string. If your string contains some percent escapes, bad things will happen. The correct, if slightly longer way is:
NSLog(#"%#", string);
Now to the point: Autoreleased objects do not have zero retain count. They have retain count 1+ and have a pending –1 operation on them that will happen “soon in the future”.
The precise meaning of “soon in the future” depends on the situation. If you’re on the main thread and there is no additional autorelease pool in place, autoreleased objects will be released on the next runloop iteration. This does not have to be the case if you have an additional release pool:
// Let’s pretend this is a long loop and you don’t want to wait
// for the autoreleased objects to be collected by the main pool.
for (…) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *foo = [NSString stringWith…];
[pool drain];
// Now foo is no longer valid.
}
As for returning autoreleased objects, that’s one of the main use cases for autoreleasing. You are returning an object that will perish “soon”, but if the caller is interested, he can retain and take over the ownership. (It’s like, if you pardon the image, passing a bomb with a burning safety fuse. If the caller is interested, he’ll put out the fuse by retaining.) And if the caller is not interested, like maybe he’s ignoring an output from a function or just uses the value to construct some other object, he does not do anything and the object will get out of memory:
- (id) createObject {
return [NSString stringWith…];
}
- (void) interestedCaller {
NSString *value = [[self createObject] retain];
}
- (void) notInterestedCaller {
[self createObject]; // maybe just interested in side effects
NSString *differentString = [NSString stringWithString:[self createObject]];
}
This is really convenient and makes the manual memory management quite pleasant. You might be interested in run loops and the Objective-C tutorial by Scott Stevenson.
Related
I am new to Objective C and here is my confusion:
When is it applicable to allocate memory for an instance?. Like this:
When is it applicable to use this...
NSString *str = [[NSString alloc]init];
and to use this...
- (NSString *) formatStr:(NSString *) str{
NSString *str = (NSString *) str;
...
.....
.......
}
and even creating UIActionSheet, it uses alloc but in other UI elements, it does not..
What exactly the reason and when shall it be done?
Thanks fellas.. :D
In addition to the "normal" allocation route (i.e. through [[MyClass alloc] init]) some classes provide so called "factory methods". These are class methods that allocate objects internally. The advantage of using factory methods is that they can create a suitable subclass to return to the caller. In both cases, though, the allocation is ultimately done by alloc/init.
Objective C's alloc method handles allocating memory, you don't have to worry about allocating, just managing the retain and release cycles.
checkout this About Memory Management article from Apple
when you create an instance using alloc+init OR you get an instance through a method that has init in the name (a convention, e.g. initWithString) you are said to own the object, this is, you must not retain it (its ref counter is already set to 1) and need to eventually release it when you are done with it. When you receive an instance by calling a method which hasn't get init in the name (rule on thumb but you should always check documentation) this means that you are not the owner of the object, i.e. the object might be released at any time, even while you are using it. Usually methods such as stringWithFormat will return autoreleased objects which will be around until the end of the event cycle (unless you claim ownership by calling retain on the string).
I strongly recommend reading the cocoa memory management guide.
NSString *str = [[NSString alloc]init]; //you own the object pointed to by str. Its retain count is 1. If you don't call release this will be a memory leak.
- (NSString *) formatStr:(NSString *) str{
NSString *str = (NSString *) str; //you don't own str. btw, you don't need casting here
//using str here might throw exception if its owner has released it
[str retain]; //you own str now. you can do whatever you want with it. It's yours
.......
}
After trying to print retainCount of object I get 2147483647. Why do I get such a result? It should be 1, shouldn't?
NSString *myStr = [NSString new];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
2011-09-08 17:59:18.759 Test[51972:207] refCount = 2147483647
I use XCode Version 4.1. Tried compilers GCC 4.2 and LLVM GCC 4.2 - the same result.
Garbage Collection option was set to unsupported.
NSString is somewhat special when it comes to memory management. String literals (something like #"foo") are effectively singletons, every string with the same content is the same object because it can't be modified anyway. As [NSString new] always creates an empty string that cannot be modified, you'll always get the same instance which cannot be released (thus the high retainCount).
Try this snippet:
NSString *string1 = [NSString new];
NSString *string2 = [NSString new];
NSLog(#"Memory address of string1: %p", string1);
NSLog(#"Memory address of string2: %p", string2);
You'll see that both strings have the same memory address and are therefore the same object.
This doesn't directly answer your question, but retainCount is not really all that useful and should not be used for testing. See this SO post for details.
When to use -retainCount?
While NSString's are an odd case (there are others in the framework) you might also run across this in other clases - it's one of the ways of creating a singleton object.
A singleton only exists once in the app and it's pretty important that it never gets released! Therefore, it will overwrite some methods of NSObject including (but not limited to):
- (id)release {
// Ignore the release!
return self;
}
- (NSUInteger)retainCount {
// We are never going to be released
return UINT_MAX;
}
This object can never be released and tells the framework that it's a singleton by having a ludicrously high retain count.
Checkout this link for more information about singleton objects.
I've seen this a couple of times regarding NSStrings, the retainCount returns the maximum count instead of the actual one when you try to look at retainCounts of strings in this manner.
Try this;
NSString *myStr = [[NSString alloc] init];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
Edit: Restored NSUInteger
If I have a method
- (void) myMethod:(NSString *)string {
[Object anothermethodWithString:string];
}
and I call
[Object myMethod:#"this is a string with no alloc statement"]
Do I need to do something like
- (void) myMethod:(NSString *)string {
NSString *string2 = [[NSString alloc] initWithFormat:#"%#", string];
[Object anothermethodWithString:string2];
[string2 release];
}
instead of the way I had myMethod before? I have misbehaving code that seems to be caused by a string being auto-released while a second method within another method is being called (like in the example). The second way I have myMethod fixed all of my problems.
So is a "non-alloc" string an auto-released string? I asked this question as a follow up to another question (which was completely unrelated and is why I am creating this post), and a few sources said that I don't need to reallocate the string. I am confused, because the behavior of my code tells me otherwise.
Dave's got it right. You only need to worry about calling release on objects that you new, alloc, retain, or copy.
The above rule works very well, but if you're curious and want to get into a lot of detail, I suggest reading the Memory management Programming Guide from Apple's docs. It's free and goes from basic concepts into a lot of details.
If you use : NSString *str = #"". It is kind of a constant, you don't need to do any memory management.
If you call from a method : NSString *str = [NSString stringWithFormat:#""], the str is already autoreleased.
If you manually alloc, init. You need to call release, or autorelease yourself.
The general memory convention is : if you do something with new, alloc, retain, or copy, you need to release it yourself, any other cases, the object is autoreleased, don't release it
Whenever I read about how to avoid memory leaks, I always came across a concept that
"Number of alloc must be equal to number of release".
But I came across a concept where we require more than one release. Like What I used to practise was as follows:
(NSString*) func1
{
NSString* result = [[NSString alloc] initWithFormat:#"Test String"]];
return result;
}
(void) func2
{
NSString* temp = [self func1];
[temp release];
}
But I came across a concept of retain count which says that in the above case the memory is not deallocated for the string since the retain count for the string is 1 at the end. So the right practise is
(NSString*) func1
{
NSString* result = [[NSString alloc] initWithFormat:#"Test String"]];
[result autorelease];
return result;
}
(void) func2
{
NSString* temp = [self func1];
[temp release];
}
So now I have two releases for deallocating the memory which is a contradictory to my above sentence which I read on most of the blogs ""Number of alloc must be equal to number of release".
I am little bit confused about the above stuff. Becoz if I autorelease the string in the first function and want to use the string in second function for a long time, and what if the release pool is flushed in between, on the other side if I dont use autorelease it will still block the memory.
So whats the correct way of doing it.
At the time you call alloc whatever is returned will have a retainCount of 1. Calling release on that object will cause it to be deallocated (it's retainCount will drop to 0). In your first example, then, the second line of func2 will deallocate the NSString* you received from func1, and your memory management chores are complete.
In the second example you are tossing result in func1 into the current autorelease pool, which will cause it to become deallocated when the pool drains. You do not want to attempt to manage the memory of that object once it has been placed into the pool- it is no longer your responsibility.
If you want to generate the string and keep it around for a while (e.g., through the lifetime of several autorelease pools), I would recommend the first form of memory management.
The correct way is this:
(NSString*) func1 {
NSString* result = [[NSString alloc] initWithFormat:#"Test String"];
// retaincount == 1
return [result autorelease];
}
(void) func2 {
NSString* temp = [self func1];
// retaincount == 1
// temp is autoreleased, therefore no [release] is necessary.
}
Autorelease is automatically done at the end of the run loop, that means it cannot be emptied while your code is doing something. -> The code you have is safe. This isn't true for multithreaded application!
(NSString*) func1
{
NSString* result = [[NSString alloc] initWithFormat:#"Test String"]];
return result;
}
[result retainCount] is 1
(void) func2
{
NSString* temp = [self func1];
[temp release];
}
[temp retainCount] is 0
No need for autorelease.
From Memory Management Rules:
This is the fundamental rule:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
The following rules derive from the fundamental rule, or cope with edge cases:
As a corollary of the fundamental rule, if you need to store a received object as a property in an instance variable, you must retain or copy it. (This is not true for weak references, described at “Weak References to Objects,” but these are typically rare.)
A received object is normally guaranteed to remain valid within the method it was received in (exceptions include multithreaded applications and some Distributed Objects situations, although you must also take care if you modify the object from which you received the object). That method may also safely return the object to its invoker.
Use retain in combination with release or autorelease when needed to prevent an object from being invalidated as a normal side-effect of a message (see “Validity of Shared Objects”).
autorelease just means “send a release message later” (for some definition of later—see “Autorelease Pools”).
In general, I'd feel safer to do a retain on a return value, like the one in the "func 2":
(NSString*) func1 {
NSString* result = [[NSString alloc] initWithFormat:#"Test String"];
return [result autorelease];
}
(void) func2 {
NSString* temp = [[self func1] retain];
// Do something with temp
[temp release];
}
Is this unnecessary? I understand that in this example "temp" is just a local variable. But it could have been an instance variable, which may need to be retained.
I'm assuming my understanding of how to perform a deep copy isn't just there yet. The same with some sub-optimal memory handling that I'm performing down below. This code below probably depicts a shallow copy, and I believe that's where my problem might be. I have some cookie-cutter code for an example that looks like the following:
NSArray *user = [[xmlParser createArrayWithDictionaries:dataAsXML
withXPath:kUserXPath] retain];
if([user count] > 0) {
self.name = [[user valueForKey:#"name"] copy];
}
// Crash happens if I leave the next line un-commented.
// But then we have a memory leak.
[user release];
[xmlParser release];
Unfortunately when I comment out [user release], the code works, but we have an obvious memory leak. The method createArrayWithDictionaries:withXPath: was refactored last night when the SO community helped me understand better memory management. Here's what it looks like:
- (NSArray *)createArrayWithDictionaries:(NSString *)xmlDocument
withXPath:(NSString *)XPathStr {
NSError *theError = nil;
NSMutableArray *dictionaries = [NSMutableArray array];
CXMLDocument *theXMLDocument = [CXMLDocument alloc];
theXMLDocument = [theXMLDocument initWithXMLString:xmlDocument
options:0
error:&theError];
NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
for (CXMLElement *xmlElement in nodes) {
NSArray *attributes = [xmlElement attributes];
NSMutableDictionary *attributeDictionary;
attributeDictionary = [NSMutableDictionary dictionary];
for (CXMLNode *attribute in attributes) {
[attributeDictionary setObject:[attribute stringValue]
forKey:[attribute name]];
}
[dictionaries addObject:attributeDictionary];
}
[theXMLDocument release];
return dictionaries;
}
I'm guessing there's a couple of issues that might be going on here:
Auto release on my dictionaries array is happening, thus my app crashing.
I'm not performing a deep copy, only a shallow copy. Thus when the user array is released, self.name is done for.
With NSZombieEnabled, I see the following:
*** -[CFString respondsToSelector:]:
message sent to deallocated instance 0x1ae9a0
Also, the final call where the backtrace shows this is crashing contains the following code in a separate module from the other two methods:
User *u = self.user;
NSString *uri = [NSString stringWithFormat:#"%#/user/%#/%#",
[self groupName], u.userId, kLocationsUri];
Between all the auto releasing/copies/retain happening between the client code and createArrayWithDictionaries:withXPath, I'm a bit confused as to the real problem here. Thanks again for helping me understand.
OK, you don't need to retain the return value from createArrayWithDictionaries: since you're not keeping it around. The return value is autoreleased. I'd strongly recommend reading up on how autoreleasing works. You only retain things that you intend to keep around in your object.
Also, user is an NSArray. If you call [user valueForKey:#"name"], you'll get another NSArray of values representing the values of the name key for each of the objects in users. Furthermore, how is the name property on your object defined? If you declared it as copy or retain (I believe retain is the default if you don't specify it yourself), you don't need to copy or retain the value. Indeed, the accessor should always be responsible for doing the memory management, not the caller. If you wrote your own accessor (i.e. you didn't use the #synthesize keyword), you need to make sure you do the memory management there.
I'm guessing what you meant to write was something more like this:
NSArray *user = [xmlParser createArrayWithDictionaries:dataAsXML withXPath:kUserXPath];
if ([user count] > 0)
self.name = [[user objectAtIndex:0] objectForKey:#"name"];
[xmlParser release];
I think your troubles are stemming from a misunderstanding of how memory management works in Objective-C.
Hope this helps.
Auto release on my dictionaries array is happening, thus my app crashing.
If the caller intends to keep the array around somewhere, it needs to retain it. Otherwise, it will crash when it tries to access the (now-deceased) object.
If the caller is going to store it in a property, it must use the self.dictionaries = […] syntax, not dictionaries = […]. The former is a property access, which calls the setter method; the latter is a direct instance variable assignment.
Coming back to your actual question, that of a deep copy: You need to get the sub-elements of every element and put them in each element's dictionary.
Basically, you need a recursive method (or a queue, but that's harder—file under premature optimization until you've proven you need it) that takes an element and returns a dictionary, and then you need to call this method on each of your element's child elements, and collect the results into an array and put that into the dictionary you're creating.
I would recommend making this recursive method an instance method of the element. Something like:
- (NSDictionary *) dictionaryRepresentation {
NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
for (CXMLNode *attribute in attributes) {
[attributeDictionary setObject:[attribute stringValue] forKey:[attribute name]];
}
NSArray *childElements = [self childElements];
return [NSDictionary dictionaryWithObjectsAndKeys:
attributeDictionary, #"attributes",
[childElements valueForKey:#"dictionaryRepresentation"], #"childElements",
nil];
}
Then you replace the loop in createArrayWithDictionaries:withXPath: with a similar valueForKey: message. I'll leave you to fill it in.
valueForKey: is Key-Value Coding's principal method. In both places, we're making use of NSArray's handy implementation of it.
(If the use of valueForKey: still doesn't make sense to you, you should read the KVC Programming Guide. KVC is vitally important in modern Cocoa, so you do need to read this sooner or later.)