About dealloc/release: is it always OK to do x = nil; [x release]; - or can it cause problems? - objective-c

since every assignment to a variable with a different object increases its retain count and in the dealloc its not always clear how often a variable got assigned a simple [maVar release] might NOT BE SUFFICIENT. So using ALWAYS myVar = nil sets the retain count to zero, and a subsequent [myVar release] will never cause a problem again. (is it actually still required ?)
The only situation when not to do it this way is if myVar is passed OUT then I must not do this, since the value gets destroyed by myVar = nil;
Is my thinking correct? Or could this way of avoiding leaks cause any other problems?

Your thinking is incorrect in quite a lot of ways. These are probably just scratching the surface:
Assignment to a variable does not increase its retain count. (There are some subtleties to do with properties, but frankly that's way beyond the level we're at here.)
dealloc is called when the retain count reaches 0.
Setting myVar = nil does not affect the retain count.
myVar = nil destroys only the local pointer value, it does not destroy an object that has been passed out.
It is safe to call [myVar release] when myVar is nil, but it isn't useful -- it does nothing.
Worrying about retain counts is always a mistake. Worry about what you own.
It is clear that your grasp of C pointers and Objective-C memory management is a bit lacking. I'd suggest doing some remedial C work before several thorough re-reads of the Memory Management docs.

Please read Apple's documentation on Memory Management.
Assigning a pointer to an object will not increment the retain count, only calling retain does that. Functions with Copy or Init in the name should return an object with a retain count of 1, other functions should return autoreleased objects that will be dealloc'd when the main loop finishes.
Setting an object to nil doesn't modify the retain count, but it will cause that memory to leak. Calling release on the pointer at that point essentially does nothing. You need to be responsible about using retain, release, autorelease, and how you name your functions if you want to effectively manage your memory usage.

Related

Dealloc and ARC

I read that when using ARC in Objective-C programming in Xcode the dealloc method is called automatically by the compiler. Under what circumstances is it called?
In order to avoid having too many variable names, when I need to repeatedly use the same classes to do multiple operations (and resetting the variable each time) I often declare the variables, set them to nil, and then assign values to them as I go. This ends up looking like this:
MyClass mc;
mc = [[MyClass alloc] init];
[mc doThis:someOption]
mc = [[MyClass alloc] init];
[mc doThis:someOtherOption];
//etc...
The method name alloc is short for "allocate" because it is the method where memory is allocated to the variable. Does the compiler automatically release the memory for sc every time I assign it a new value? I plan on using this method in a project of mine, and I don't want a lot of memory being allocated with all the times I call alloc to assign a new value to mc.
The compiler never calls dealloc. The compiler inserts retain, release and autorelease (more efficient equivalents, really) as necessary to follow the memory management rules.
When the compiler inserts said calls is up to the compiler and the details will change across different compiler versions and different optimization levels.
I.e. you shouldn't need to worry about it in general.
However, autorelease pressure can still be an issue, as can retain cycles. Thus, you should definitely poke about your app with the Allocations Instrument to both measure the high-water mark and make sure your app isn't leaking memory over time.
I read that when using ARC in Objective-C programming in Xcode the dealloc method is called automatically
In Objective-C, you never call -dealloc directly whether or not you're using ARC.
Under what circumstances is it called?
-dealloc is called when an object's retain count drops to zero. That is, it's called when all the objects that had previously asserted "ownership" of the object (by calling +alloc or -retain or -copy or +new) have renounced that ownership (by calling -release or -autorelease).
Does the compiler automatically release the memory for sc every time I assign it a new value?
If you're using ARC (and you should be), the compiler will insert appropriate calls to -retain, -release, etc. so that memory is managed appropriately. That said, you still need to understand how memory management works, and you should be familiar with the material in Advanced Memory Management Programming Guide.
Under ARC, your variable mc will hold a strong reference to only one instance of MyClass at a time, so when you allocate the second one and assign it to the variable, the first one should be getting deallocated, assuming your doThis: method doesn't do something that will create another strong reference to that instance, or that you're not doing anything else in your code that you've omitted that will keep a strong reference.
That being said, it would be a good idea for you to run your app with Instruments to see how much memory your app uses during this. Your instances shouldn't be getting autoreleased, so you shouldn't have to worry about them remaining around until the autorelease pool is drained, but I don't know what you might being doing when you init an instance of the class, or what you might be doing in your doThis: method, so if you're concerned, it's always a good idea to profile it with Instruments for memory allocations and leaks.

How does retainCount work?

I have a problem with retainCount
NSLog(#"%i", [self.albumReceiver retainCount]);
self.albumReceiver = [[[FacebookAlbumsDelegateReceiver alloc] init: self] autorelease];
NSLog(#"%i", [self.albumReceiver retainCount]);
The retain count on the first line is 0 but when it gets to third line is 3.
The property on self.albumReceiver is retain property... But as far as i can see it should be 2 where other later retain count should went to 1 since it was autorelease later.
NSLog(#"%i", [self.albumReceiver retainCount]);
albumReceiver = [[[FacebookAlbumsDelegateReceiver alloc] init: self];
NSLog(#"%i", [self.albumReceiver retainCount]);
the retain count start with 0 and in this case the second retain count print 2....
Can somebody give some idea of how this retain and release work....
I thought without 'self' keyword, it will ignore the setter call is it? But if i put autorelease on the second example, i will have error.
Firstly, the retain count is an implementation detail that you should not be overly concerned with. You should really only care about ownership.
Having said that, the explanation for what you are seeingis as follows:
The retain count on the first line is 0
That's because self.albumReceiver is nil at that point. On real objects, you will never see a retain count of 0 (in the current implementation of Foundation).
when it gets to third line is 3
Normally you would expect the retain count to be 2, +1 for the alloc and +1 for assignment to a retain property. However, the init: method might cause some other object to retain it, so might the setter for the property. Another object observing the property might choose to retain the object too. In short, unless you know the exact implementation of all the methods involved and you know for sure nothing is using KVO on albumReceiver, all you can say about the retain count is that self has ownership of it (NB ownership is not exclusive, other things may also have ownership). This is why you shouldn't pay too much attention to retain counts.
Can somebody give some idea of how this retain and release work
Yes. You need to think in terms of ownership. Certain methods give you an object that you own. These are any method starting with alloc, any method starting with new, any method starting with copy or mutableCopy and -retain. If you receive an object in any other way, you do not own it. That includes receiving them as a return result of a method, ass parameters of a method or as by reference parameters of a method or as global or static variables.
If you own an object, you must relinquish ownership by either releasing or autoreleasing it, or it will leak. If you do not own an object, you must not release or autorelease it.
I find that it is best to think of "you" in the above as meaning "the scope in which the object reference was declared".
Anyway, I recommend you to read Apple's Memory Management Rules for the definitive explanation and not to trust answers here. If you look at the original edit for this answer, you'll see that I got the rules slightly wrong because they have been tightened up since I last read them.
Do not use retainCount. (For situations where it’s appropriate to use it, see this website.) Further reading: blog post by bbum, previous SO thread one, thread two. Also note that retainCount is deprecated in recent SDKs. It’s a good idea to pay attention to the deprecation warnings, and even better idea to turn all warnings into errors.
It is generally a bad idea to pay any attention to the retainCount of an object in Objective-C because it is usually impossible to know which secret parts of the frameworks feel a need to retain the object.
In the case you cite where you are adding the object to the autorelease pool, the autorelease pool will presumably be retaining the object until it comes time to flush the pool (during the runloop). This probably explains why the retain count is higher for the autoreleased object.
Note the use of the words "presumably" and "probably" in the above paragraph. I have no idea if this is actually what is happening inside the Cocoa/Cocoa Touch frameworks. This is the problem with using retainCount, you have no way of knowing what the retain count should be at any moment.
If you retain the object (or create it with a method name that contains alloc, copy, mutableCopy or new), you release it. The frameworks are free to also retain the object and they will release it when they are ready. When the retain count reaches zero it will be dealloced.
Update: Having looked at the GNUStep source code for NSObject and NSAutoreleasePool my possible explanation above probably isn't what is happening. However, I have no way to check for sure because I can't see Apple's implementation of these two objects. Even more reason not to trust retainCount or any inferences from it.
The only rule that really exists in environments with manual memory management is
If you use alloc, copy, mutableCopy, new
release it. Otherwise DON'T. retainCounts don't really work for debugging. See here

release , in Objective C

What I am doing is to check the retainCount after allocating the obj and after releasing this obj. Like below
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
TestClass *ptr = [[TestClass alloc] init];
NSLog(#"retain count of ptr is %d",[ptr retainCount]);
[ptr release];
NSLog(#"Right after release:::::retain count of ptr is %d",[ptr retainCount]);
}
What is getting after display on the console is
2012-05-11 13:51:09.515 memoryManagement[1807:f803] retain count of ptr is 1
2012-05-11 13:51:09.516 memoryManagement[1807:f803] Right after release:::::retain count of ptr is 1
I don't why the retainCount after releasing is still 1. Should it be 0.
Please advice me on this issue and point out if I have just made a mistake in my code.
The first rule of Cocoa Club is: don't use -retainCount. The second rule of Cocoa Club is don't use -retainCount.
First off, if you think you need it, you almost certainly don't. If you are using it to debug, you are using the wrong tool. If you are using it for application logic, you have a broken design.
Second, if you have to ask a StackOverflow question about it, you definitely don't need it.
Third, it's subtle, unreliable, can do wacky things behind your back, and generally will cause more headaches than you can possibly imagine. I recommend Bill Bumgarner's blog post.
The actual retain count of an object can never be zero, because when it's zero, nothing has a reference to it, and it is deallocated. The memory doesn't actually get cleared, though, and it looks like the internal release code doesn't bother actually decrementing the count.
Further, you're violating memory management rules; you've got an object that you own, which you then release. You're not allowed to interact with that object through that pointer anymore.
Nothing to see here, and don't bother looking at an object's retain count.
You have an even worse problem than using retainCount.
Never send messages to objects you release -- especially if you have some reason to think their retainCount is really 1. Maybe release is written something like this:
-(void) release {
if ([self retainCount] == 1) {
[self dealloc];
}
else {
// reduce the retain count
}
}
In that case, the object is gone. You send the message, and if the object is somehow still living in deallocated memory, it would report a retainCount of 1 -- no one says release needs to decrement it if it's being deallocated (who would know?).
Once you call release -- you promised never to send messages to the object -- if you break your promise, anything can happen.
The Apple docs explain why retainCount is not what you think it might be
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html
Important This method is typically of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
The docs also explain whey you sometimes see a giant number instead of what you think the retainCount should be:
For objects that never get released (that is, their release method does nothing), this method should return UINT_MAX.
This has nothing to do with your case though. If you call retain on ptr right after you init, you will likely see the retainCount as 2 and 1 (or N and N-1), but are not guaranteed that this is true. retainCount is more logical than a lot of these answers would have you believe, but it can't be used in the way you want to reliably.
Never use retainCount. It is confusing and never gives you a clear answer. Also, If you are correctly following memory management guidelines, you would never need to use retaincount.
On most occasions, it gives you ambiguous output.
Eg. [NSString stringwithstring:#"apple"] has a garbage value as retaincount like 1124523415 etc.
So, never trust retainCount.

Conditions in which retainCount increases or decreases

I have read that objects retain count and that it can be increased when we assigned a second value (or object).
Can anybody give me an idea about the basic conditions where retainCount increases or decreases (without retain , alloc and release)...
Short answer: no.
Slightly longer one:
Actions on your part that are typically expected to modify the retain count are retain, release, autorelease and calling methods whose name contains new or copy. In some instances, however, they might not do so, for good implementation reasons, but do something else instead. And there are many other things you can do, like adding objects to collections, that may modify the retain count in ways that are just not your business.
Do not use or rely on retain counts. They are an implementation detail.
Your concern is to manage your own ownership, which you do via the semantics of the above-mentioned methods. How that affects the retain count beneath the hood is something you are better off not even looking at.
Please just don't.
Being concerned about retain count is almost always a way to cause bugs, not cure them.
The retain count of an object is an implementation detail that you shouldn't worry about. You should really only concern yourself with when you gain and lose ownership of an object. Here's why:
+alloc returns an object with a retain count of 1. However, you immediately send it an init message which might give you back a completely different object. For instance
NSString* foo = [[NSString alloc] initWithString: #"foo"];
Gives you an object with a retain count of 1, right? Wrong on current implementations of Cocoa. The string returned by +alloc is immediately released and instead a reference to #"foo" is returned. The retain count of #"foo" is INT_MAX.
Retaining an object increases its retain count, right? Probably, but again sending retain to constant strings has no effect and some singletons have a nul implementation of retain too.
Similarly release usually has an effect on the retain count, but again not necessarily for the same reasons.
Sending copy should give you a new object with a retain count of 1 right? Wrong. Immutable objects can implement copy by sending themselves retain and then returning themselves. In most cases, that will add one to the retain count, but of course with string constants, nothing happens.
If you just think in terms of retaining and releasing ownership all of that stuff I have just said becomes irrelevant implementation details.
retainCount of an object changes in the following cases:
When you create an object(new or
alloc, copy or mutablecopy), it has a
retain count of 1.
When you send an object a retain
message, its retain count is
incremented by 1.
When you send an object a release
message, its retain count is
decremented by 1.
When you send a autorelease message
to an object, its retain count
will be decremented by 1(not
immediately as in case of release but
some time in the future)
You can view this post to get a detailed info on how memory management works in iPhone.

Accessor method object management?

After reading the Memory Management Guide I am trying to get my head around what is happening here My understanding "so far" is ...
- (EngineClass *)engine {
return [[engine retain] autorelease];
}
I am returning a pointer to an Engine object.
The retain count of the object is incremented to record we are making a new pointer to the object
Balance the above retain by specifying an autorelease at some future point.
Am I on the right track?
cheers -gary-
I'm not sure I'd say the retain is "to record we are making a new pointer to the object."
The retain-autorelease pair is there to indicate that there's another object interested in the return value, so it needs to stick around at least that long, but the other object doesn't properly own the return value. Without the retain, if the object performing this method is deallocated immediately afterward, the engine might not have any other owners and would also be deallocated immediately. That's not the expected behavior. Doing it this way causes the object's ownership not to go away until the autorelease pool is drained.