NSArray release crashes with EXC_BAD_ACCESS - iphone

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.

Related

Objective-C pointers/memory management question

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.

What happens after I release a deallocated object?

I created
object *Obj = [[Obj alloc] init];
Obj retain count is 1. After I release it, the object is deallocated.
If I try to release the object again, what will happen?
EXT_BAD_ACCESS most likely since your object reference is no longer valid.
The code may crash. But it may just as well work most of the time.
You brake a rule, you may get caught. But you may just as well get away with it, living in constant fear that you may get caught later on.
There’s an important distinction to be made here: you can’t release the object again, because the object no longer exists. If you send another message to the variable (be it release or any other message), the behaviour is undefined because the variable is no longer known to point to a valid object. (It’s possible that the address the variable now points to will have been reused for a different object, in which case it may not crash, but of course that’s still a bug.)
Once the retain count of an object reaches 0, it is released, and all further attempts to access it will result in random behaviour.
If you use autorelease instead, the retain count will not be lowered, and the object will be put in the autoreleasepool. The object will only lower its retain count once it reaches the autoreleasepool drain command, which is usually done on a much higher level in a much broader scope. If you really need the object after the autoreleasepool is drained, you should retain it before drain is executed, or else it will have exactly the same behaviour as in my first paragraph.
Get EXT_BAD_ACCESS. Because of you are already release it and now try to release again.
your object reference is no longer valid.

Why is the retainCount still 1 after [object release]?

NSLog(#"first:%u",[object retainCount]);
[object release];
NSLog(#"second:%u",[object retainCount]);
Output:
first:1
second:1
Why doesn't the object get released?
a Quote from NSObject reference on retainCount method
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.
Object can be released but not when you think it will be. Basically, don't look at retainCount. It may not change until the next runloop or at all, it's an implementation detail. You will get a sense for when you need to release and when you don't with experience but until then rely on the clang analyzer.
First, retainCount doesn't give you a number you can use. It's meaningless.
Second, the reason the retainCount is 0 is probably that you try to work with an object that doesn't exist anymore. You're lucky your application doesn't crash, because your accessing invalid memory. Decreasing the retainCount just before deallocating an object is unnecessary, therefore Apple doesn't do it, probably.
Divide any number by zero and you will find the meaning of "object with retain count of zero".
I agree with the other comments about not using retainCount to get a reliable count.
EDIT: Ignore my stupidity below... :)
However, I've observed that setting the corresponding property to nil...
self.object = nil;
the retainCount does tend to be decremented immediately.

Is release without prior retain dangerous?

I have some code which I think has extra release statements.
Is the code incorrect?
What is the end result?
I don't understand memory management well yet - even after reading lots of articles and stackoverflow answers. Thanks for straightening me out.
Update: The attached snippet works fine, but other code has the over-release problem
NSMutableArray *points = [NSMutableArray new];
for (Segment *s in currentWorkout.segments) {
[points addObjectsFromArray:[s.track locationPoints]];
}
[routeMap update:points];
[points release];
Your code is correct, but inadvisable. new acts as an implied alloc, which creates the object with a retain count of 1.
I think the last time I used new was in 1992; it's not wrong, but alloc/init is considered better practice, because it is clearer what you are doing. Please read Apple's guide to memory management, it is a comprehensive summary of the situation.
No messages can safely be sent to a deallocated object. Once an object has been released a sufficient number of times, it's deallocated. Any further messages sent to that object are going to an object that isn't there anymore. The precise result isn't completely predictable, but it usually ends in a crash. If you're less lucky, it could end in much stranger ways — for example, you could theoretically wind up with an Object A getting dealloced early and Object B allocated in the same memory location, then Object B receiving messages meant for Object A that Object B does understand but isn't supposed to receive at that time.
Basically, follow the rules. Think of it in terms of ownership. If you've claimed ownership, you need to release that ownership. If you don't own the object, you must not release it.
Take a look at this article online: http://weblog.bignerdranch.com/?p=2 .
It seems to imply that calls to release without a corresponding preior call to retain will result in a BAD_ACCESS error.
A short answer is, if you increasing the retain count of an object and you no longer are using it you should release it, otherwise you shouldnt...
So when ever you do a [objectName alloc] you are increasing the count by 1, when you use such methods as [NSString stringWithString:] these methods return an autoreleased object so you dont need to release it...if you instead did something like [[NSString stringWithString:]retain] then you are increasing the strings retain count and you should release it after you are done using it.
Im not too sure if new increases the reference count (i suspect that it would), you can always check your retain count by doing [object retainCount]... though note that even if the retain count is greater than 0, it does not mean you need to release the object, because some other class might have a reference to the object and therefore has its retain count increased by one and its the responsibility of the other class holding the reference to release it.
Hope this helps
you should use:
NSMutableArray *points = [[NSMutableArray alloc] init];
[...]
[routeMap update:points]; //if routemap stores the points, it will need it's own release retain
[points release]; //if there is a retain in the method above, reference will not be cleared
if unsure, use the build->analyze command, it will search your code for leaked references
you can get the official memory management guide from https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html

iphone memory management issue

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.