From the Blocks documentation:
In a reference-counted environment, by
default when you reference an
Objective-C object within a block, it
is retained. This is true even if you
simply reference an instance variable
of the object.
I am trying to implement a completion handler pattern, where a block is given to an object before the work is performed and the block is executed by the receiver after the work is performed. Since I am being a good memory citizen, the block should own the objects it references in the completion handler and then they will be released when the block goes out of scope. I know enough to know that I must copy the block to move it to the heap since the block will survive the stack scope in which it was declared.
However, one of my objects is getting deallocated unexpectedly. After some playing around, it appears that certain objects are not retained when the block is copied to the heap, while other objects are. I am not sure what I am doing wrong. Here's the smallest test case I can produce:
typedef void (^ActionBlock)(UIView*);
In the scope of some method:
NSObject *o = [[[NSObject alloc] init] autorelease];
mailViewController = [[[MFMailComposeViewController alloc] init] autorelease];
NSLog(#"o's retain count is %d",[o retainCount]);
NSLog(#"mailViewController's retain count is %d",[mailViewController retainCount]);
ActionBlock myBlock = ^(UIView *view) {
[mailViewController setCcRecipients:[NSArray arrayWithObjects:#"test#recipient.com",nil]];
[o class];
};
NSLog(#"mailViewController's retain count after the block is %d",[mailViewController retainCount]);
NSLog(#"o's retain count after the block is %d",[o retainCount]);
Block_copy(myBlock);
NSLog(#"o's retain count after the copy is %d",[o retainCount]);
NSLog(#"mailViewController's retain count after the copy is %d",[mailViewController retainCount]);
I expect both objects to be retained by the block at some point, and I certainly expect their retain counts to be identical. Instead, I get this output:
o's retain count is 1
mailViewController's retain count is 1
mailViewController's retain count after the block is 1
o's retain count after the block is 1
o's retain count after the copy is 2
mailViewController's retain count after the copy is 1
o (subclass of NSObject) is getting retained properly and will not go out of scope. However mailViewController is not retained and will be deallocated before the block is run, causing a crash.
Do not use -retainCount.
The absolute retain count of an object is meaningless.
You should call release exactly same number of times that you caused the object to be retained. No less (unless you like leaks) and, certainly, no more (unless you like crashes).
See the Memory Management Guidelines for full details.
(cribbed from one of #bbum's answers)
As for your question:
Are you actually observing a crash? Or are you just shooting blindly from the hip and thinking that it might crash?
From the code you posted, it would appear that mailViewController is an instance variable, in which case the block would be retaining self instead of the instance variable. And since you autoreleased your instance variable, it's getting cleaned up by an NSAutoreleasePool just like you'd expect.
So in summary:
Do not use -retainCount.
Do not autorelease instance variables that you want to exist beyond this turn of the run loop.
edit A bit more clarification:
Here's what's going to happen when your block is created:
Inspect object references in its scope. There are two: self->mailViewController and o.
self->mailViewController is a member of a struct (self), so it is not retained directly. Retain self instead.
o is a local variable. Retain it.
This is proper behavior. As for your code...
o is created with a +0 retain count
self->mailViewController is created with a +0 retain count
myBlock is created with a +0 retain count. o now has a +1 RC, as does self. self->mailViewController still has a +0 RC
myBlock is copied => +1 retain count
Fast forward to the end of this run loop cycle.
The current autorelease pool is drained. All objects with a +0 retain count are deallocated, including self->mailViewController. self->mailViewController now points to deallocated memory, and is essentially garbage.
Fast forward to some future point when myBlock is executed
myBlock attempts to invoke a method on self->mailViewController. However, self->mailViewController no longer points to a valid object, and your app crashes.
However, if mailViewController is not an instance variable, then we need to see more code. I think it'd be highly unlikely that the behavior you're seeing is a problem with the blocks runtime, but it is possible.
The documentation no longer says that. It now correctly says:
In a manually reference-counted environment, local variables used
within the block are retained when the block is copied.
As the "mailViewController" is a member of your current class instance, so the block actually retain "self" here.
Related
I have a bit of confusion about retain and release variable.
These are my question:
I have an object A allocated
Object *A = [[Object alloc] init]
Does this increase the retain count? Is it the same as having
Object *A = [[[Object alloc] init] retain].
I know if we call retain, the object will be held until we released it.
2.1.
I have a retained Object A. This Object A was passed to a function as an argument. Later in the function I released it. Will it release the memory of the Object A? if it is, does the Object A no longer existed.
2.2
Follow on with 2.1, instead of releasing Object A. I created a local variable Object *B = A. If I released Object B will it also release Object A. Or if I retain B, will it retain A as well.
I am a bit of confused so I want to ask anyone here to directing me to the right path.
Thanks
Object *A = [[Object alloc] init] Does this increase the retain count?
Yes, more specifically, likely, it initializes the retain count to 1.
Is it the same as having Object *A = [[[Object alloc] init] retain]. I know if we call retain, the object will be held until we released it.
Not the same. That will increase the retain count twice. There's not much reason to increase the retain count twice in the same place. If you did do that, you'd be responsible for calling release twice.
I have a retained object A. This Object A was passed to a function as an argument. Later in the function I released it. Will it release the memory of the Object A? if it is, does the object A no longer existed.
First, you should make sure that you understand that whether release frees memory or not depends on if there are other owners that are holding a reference to the object. If more than one thing has retained the object, then release will not free the memory in that case.
Second, bad idea. To keep sanity with reference counting, you should follow certain patterns.
retain (or alloc) instance variables, release them in dealloc or before.
retain (or alloc) local variables if needed, and release them before you exit the method.
The caller does not own the return value of a function. That implies that you handle a function return value like a local variable, but autorelease it before you return it instead of releasing it. That ensures it will last at least long enough for the caller to retain it, if needed.
One of the patterns is not for a method caller to own a reference to a method argument, but when the function returns the caller does not own the reference. The method should not release the caller's reference.
Follow on with 2.1, instead of releasing Object A. I created a local variable Object *B = ObjectA. If I released B will it also release Object A. Or if I retain B, will it retain A as well.
retain and release are sent to objects, not references. A and B refer to the same object, so it's the same calling retain or release on one as on the other.
It is legitimate, but probably unnecessary, to [B retain] and later in the same method [B release]. But do not do [B release] only, thereby expropriating A's ownership of the object.
Remember this: NARC.
New, Alloc, Retain, Copy are the 4 commands that will increase the retain count. In other words, for every NARC, you need a corresponding release to release that memory.
Calling alloc (or new) increases the retain count. If you retain again after that, that increases it once again. There is no need to do that second retain except for specific wanted cases.
The main rule is : the one that alloc is the one that release. Of course you can bypass that if you reaaly know what you are doing.
I have a retained object A. This Object A was passed to a function as
an argument. Later in the function I released it. Will it release the
memory of the Object A?
Basically, Yes.
if it is, does the object A no longer existed.
Yes again, but sometimes, it remains "in memory" so calls to it may work for a very very short time. Very short.
Follow on with 2.1, instead of releasing Object A. I created a local
variable Object *B = ObjectA. If I released B will it also release
Object A. Or if I retain B, will it retain A as well.
if you retain B, then the object references by A is retained twice. so releasing B does not free the object referenced by A. But if you don't retain B, then releasing B equals to releasing A (only one retain count).
Tip
Imagine that any reference you declare (Balloon* rope) is a rope you get in your hand to retain a Balloon object that contain things. The rope is not the object. The object (the balloon) is created somewhere in memory (here in the space). If you retain a second time, you get another rope to that balloon and get it in the other hand. To free the balloon, you need to free both ropes.
Note that alloc (or new) creates a rope so the balloon you've just created does not go immediatly in outerspace.
Is that clear ?
1) init is not the same as retain.
The init method actually puts the object in a correct "initialization" state so that the object can be used by calling the parent classes init method, as well as setting up any additional setup that is placed in the init method implemented in the objects .m file. The retain actually just increments the retain count by 1.
2) 2.1) When you allocate memory for an object, you want to release it in the same scope per say, so when you pass in an object into a method you wouldn't release it there. However, if you did release it in the function/method where it was passed in since you are passing in an object reference, it will be released. You can't be entirely sure when the object itself will cease to exist though.
2.2) When you say Object *B = ObjectA you aren't actually creating another object, but are creating a new reference or pointer to ObjectA. If you call release/retain on the reference B, since it's pointing to the same object as ObjectA, it's the same thing as calling release/retain on ObjectA.
I am testing the following code below. ffv is declared in the interface file.
ffv = [[FullFunctionView alloc] initWithFrame:self.view.bounds];
NSLog(#"%i", [ffv retainCount]); // prints 1
[self.view insertSubview:ffv belowSubview:switchViewsBtn];
NSLog(#"%i", [ffv retainCount]); // prints 2
[ffv release]; // you can release it now since the view has ownership of ffv
NSLog(#"%i", [ffv retainCount]); // prints 1
if (ffv == nil)
NSLog(#"ffv is nil");
// "ffv is nil" is not printed
[ffv testMethod]; // "test method called" is printed
this is my [ffv testMethod] implementation
- (void)testMethod
{
NSLog(#"test method called");
}
What I deduce in this case is that even if you release an object with retain count 2, you lose ownership of that object however, the reference is still kept.
Now, my question are:
Is my deduction correct?
Is there anything else important that can be deduced from this?
What are the complications caused by still keeping (using) ffv and calling methods from ffv? (My opinion is that this is ok since the view will always own ffv and won't release it until someone calls viewDidUnload. And as long as I don't pass ffv's reference to other objects.)
There are a couple of problems with using ffv after you have released it and it's only retained by your view controller's view.
1) It introduces a potential for future bugs, because later you might not remember that ffv is otherwise not retained. When you release the view (e.g. by replacing it with another view), you have a dangling pointer that you still hold a reference to.
2) In the special case of a UIViewController the view could be released at any time (you usually never call viewDidUnload yourself). The default behavior of UIViewController, when receiving a memory warning and the view is currently not visible, is to release the view, so unless you set the reference to nil in viewDidUnload, you have a dangling pointer again, even though you never explicitly released the view yourself.
1) Is my deduction correct?
Your deduction is correct. The Memory Management Programming Guide explains that each object has one or many owners. You own any object you create using any method starting with alloc, new, copy, or mutableCopy. You can also take ownership of an object using retain. When you're done with an object, you must relinquish ownership using release or autorelease.
Releasing the object doesn't change the value of any variables that reference that object. Your variable contains the object's memory address until you reassign it, no matter what retain count the object has. Even if the object's retain count goes to zero, causing the object to get deallocated, your variable will still point at that same address. If you try to access the object after it's been deallocated, your app will normally crash with EXC_BAD_ACCESS. This is a common memory management bug.
2) Is there anything else important that can be deduced from this?
Nothing comes to mind.
3) What are the complications caused by still keeping (using) ffv and calling methods from ffv? (My opinion is that this is ok since the view will always own ffv and won't release it until someone calls viewDidUnload. And as long as I don't pass ffv's reference to other objects.)
When you call release, you are telling the Objective C runtime that you no longer require access to the object. While there may be many cases like this one in which you know the object will still exist, in practice you really shouldn't access an object after calling release. You'd just be tempting fate and setting yourself up for future bugs.
I personally don't like peppering my code with release statements, because I don't trust myself to remember them 100% of the time. Instead, I prefer to autorelease my variables as soon as I allocate them like this:
ffv = [[[FullFunctionView alloc] initWithFrame:self.view.bounds] autorelease];
This guarantees that ffv will exist at least until the end of the method. It will get released shortly thereafter, typically before the next iteration of the run loop. (In theory this could consume excessive memory if you're allocating a large number of temporary objects in a tight loop, but in practice I've never encountered this case. If I ever do, it will be easy to optimize.)
The object is not deallocated until the retain count goes to 0. As long as it's not deallocated, you can keep using it without trouble. By retaining it you ensure that it won't be deallocated under your feet; however, if you retain another object that you know retains the first object, you can get away with this form of "indirect retaining". Don't complain when you move things around later and things start breaking, though.
if (ffv == nil)
NSLog(#"ffv is nil");
// "ffv is nil" is not printed
That's correct, releasing an object does not set the pointer to nil even if it is dealloced at that time. Good practice is to always set your pointer to nil after you release it.
You are correct to say that after you released it, it wasn't dealloced because the view still had a retain on it. But that's not how you should be thinking about it. If you want to use that object and you want it to be alive, retain it. Doesn't matter who else is retaining it. Your object has nothing to do with those other objects. You want it, retain it. You're done with it, release it and set your pointers to nil. If you don't set it to nil and everyone else also released it, you will have a dangling pointer to an object that was dealloced, and that will cause you a crash and much grievance.
so this:
[ffv release]; // you can release it now since the view has ownership of ffv
ffv = nil; // you released it, so that means you don't want it anymore, so set the pointer to nil
if you still want to use it, don't release it until you're done with it.
Well, I'm not sure 'losing' ownership is the right term. In Objective-C you have to carefully marshal your ownership of the object. If you create or retain an object, you are responsible for releasing it (either directly or via an autorelease pool). When you call release however, you don't lose a reference to the object, if something else has retained it, it will still be in memory, and your pointer will still potentially point to it.
You have a pointer ffv which is just a pointer to some memory, and you have the object which is created in the first line that ffv points to.
By calling release, you are stating that you no longer require the ponter ffv to point to a valid object, that in this context you would be happy for the object to be deallocated. The pointer still points to that bit of memory, and it is still there because its retain count was increased by assigning it to the view.
The line [ffv testMethod] is in danger of not working, as it follows the release and may not point to a valid object. It only works because something else is keeping it alive. ffv still has the same address value that it had when it was first assigned.
So in order:
Your deduction is correct.
Not really.
You shouldn't use ffv after the release call. You have no guarantee that the object is going to be there for you.
These are pointers we are using here, not references like you find in Java or C#. You have to marshal your ownership of the object, you create it, have some pointers to it and by careful management of retain and release calls you keep it in memory for as long as you need it.
Do methods retain the arguments that are passed? If so, can I release these arguments in the next line? And if not, then when do I release these objects (in case I am allocating these locally)?
The language will not retain arguments automatically. However, code that obeys the rules will retain or copy anything that it needs to keep around after execution leaves its scope.
In other words:
id object = [[SomeClass alloc] init];
[otherObject doSomethingWithObject:object];
[object release];
This code should always be OK, because if doSomethingWithObject: needs to keep its argument around, it will send it retain, and if it doesn't, it won't.
No, they simply handle the object, they don't control the memory.
You should release something in the method it was created.
Or, if it's a property or an ivar, you should release it in the dealloc (if it is retained).
Methods do not increment the reference count. However if you assign it to a variable with retain count then you need to explicitly send a nil message to both. Release of a variable can be done when you no longer want to use it. So a allocated variable will have its reference count incremented whenever a retain message is sent to it. So you need to send equal number of release messages till reference count becomes zero.
Another puzzler. I have an NSArray (iTours) containing 3 Objects and a retain count of 1.
This Array is released in the object dealloc method as follows:
- (void)dealloc {
NSLog(#"retain count für iTouren: %d", [iTours retainCount]);
[iTours release]; // triggers EXC_BAD_ACCESS
[super dealloc];
}
The console window shows the following message (no further details):
Program received signal:
“EXC_BAD_ACCESS”.
any clues what's going on? What did I miss?
Most likely, you are over-releasing iTouren and, thus, that call to release is causing the crash. That is, iTouren is already deallocated by the time you release the containing array and when that containing array sends release to the already deallocated iTouren your app crashes.
(Of course, iTours might be the object that is already deallocated. In any case, it is an over-release problem.)
Turn on zombie detection and see if that barfs up the specific problem.
Note that the number returned by retainCount is useless. Absolute retain counts are an implementation detail and will often be a specific value that seems like nonsense.
In this case, the final release of an object does not decrement the retain count. Why? Because that'd be a wasted cycle when the object is about to be deallocated anyway. It would be impossible for retainCount to return 0 because, by definition, an object with a retain count of 0 has already been deallocated and, thus, is no longer a viable message receiver anyway.
Never, ever, ever, rely on the retainCount method.
Ever.
Did I mention ever?
One is iTours the other one iTouren. You are logging a different object than that being released.
Assuming iTours and iTouren are different objects (namely that iTours is an NSArray containing iTouren), you've over-released iTours; maybe you had a failure in a setter and iTours was released without being reassigned and retained.
Be sure that your array does not contains itself. Releasing an array also release every object in it. Of course, if this is the case, the array should have a release count of two before you release it because arrays retain their elements.
A released and deallocated object will have a retain count of 1. A non-released object about to be released and deallocated will also have a retain count of 1. (Assuming memory is ever allocated for the object, some strings and numbers are never allocated, implementation detail that changes per Mac OS X release)
When an object is deallocated in current versions of Mac OS X, the memory is marked as free, nothing about the object is modified (unless you tell it to be). Thus, the retain count remains identical to the retain count before it was released.
This is the make a mistake and DIAF approach that help makes Mac OS X so solid.
How to check if an object has been released from the memory?
I know a object has to be released manually when we use alloc|copy|retain to create that object. if use the instance class method (NSString stringwithformat:), the object will be released automatically by NSAutoRealeasePool, however, sometime there have some object used to release at the (void)dealloc function there.
Can anybody tell me
What is the difference between [object release] instantly after alloc function, [object release] at (void)dealloc,and NSAutoReleasePool to release the object?
When is the (void)dealloc function being called and when is the NSAutoReleasePool release the memory, I know it is every loop cycle, how can I check it from code?
When I declared a variable in the header and set the property as retain, I still can use the alloc function to that object but not cause a memory leak, but from this post it seems like once declared a retain object at header, then you no longer can alloc the object because both will retain the object,can anybody tell me why I still can code like this without causing any memory leak?
[object release] releases your object immediately. After sending a release message you should not use the object again - unless you absolutely know you still have a retain on that object. If yours was the last retain the memory could be freed during the call to release.
Autorelease frees an object 'sometime later' the system does not guarantee anything about the meaning of 'later' other than that it will be after the scope of the current message.
See above, there is no real qay to guarantee when dealloc is called following autorelease from the point of view of your code. You should just assume it is sometime after the return of the method where you send the autorelease message.
You simply need to balance retain and release. If you have one to many (as is likely i nthe situation you describe) that is a leak. Conversely if you have unbalance the other way, you will generate a more destructive error when you access freed memory.
The correct sequence for a retained property is:
alloc init // retain == 1
set the property // retain == 2 due to setProperty calling retain.
release the object // retain == 1
Which leaves a retain count of one, no memory leak.