Feb 19

Ah, the most dreaded error. Your app crashes unexpectedly and the only output you have is EXC_BAD_ACCESS. Not a lot of information, and for someone from a Java or other higher level language background it can be very frustrating to track down. First of all, make sure you are running in debug mode always (even if you don’t have any breakpoints). This will give you a stack trace of what generated the EXC_BAD_ACCESS. Again, this may not actually tell you where the problem lies, because all EXC_BAD_ACCESS is telling you is that you are attempting to reference a pointer that is no longer valid. Therefore, at some point previous (unknown where or when) you blew away a pointer you shouldn’t have. Here are the three most common (in my case, at least) causes for these, and how to help mitigate or track them down.

Over Release – You’ve released an object, its retain count has gone to 0 and you try to access it. This is probably the most common thing that bites you when first starting out with Objective-C while learning how to manage memory. The stack trace will at least given you an idea of what object is over released (it may be an object owned by the one pointed to in the stack trace), and if you have designed your code well, encapsulation should keep you from having too many places to check. And trust me, encapsulation is key to minimizing the pain here, if you are throwing references around all over the place retaining and releasing, you are in for a world of hurt.

Once you have all the places that retain/release occur for that object, just make sure you have a one to one ratio. Apple provides a great Memory Management Document and is highly recommended. Pretty much, the gist of calling release is do it ONLY if you call retain, alloc or copy. That simple (but still easy to forget).

dealloc – This is one that bit me, and took awhile to track down. When you override dealloc on an object, remember to call [super dealloc] as this cleans up the object up the chain until it reaches NSObject and does the low level cleanup. When overriding, you need to release any objects you are managing as well. However, my biggest lesson learned here, is calling [super dealloc] LAST. I had called [super dealloc] before releasing my objects and started getting EXC_BAD_ACCESS errors. So, I spent multiple hours trying to track down a retain/releases inconsistency. Until finally realizing, that by calling [super dealloc] before cleaning up my objects, I had lost my reference to those objects.

stringWithFormat – If your stack trace is pointing to a bit of code where you are constructing a NSString via stringWithFormat, confirm that you are not trying to send a primitive (int, float, BOOL, etc) to %@. The runtime is attempting to access memory at a location of the primitive’s value. Let’s just say, I’ve done this more than once.

Those are the top three items that cause me grief with a EXC_BAD_ACCESS and the first three things I check when it appears.

Tagged with:
Jul 29

When retaining an object it is important to know the relationship of that object to the object retaining it. If you are not careful, you can enter a retain cycle, that will not allow an object to be deallocated. Matt Gallagher at Cocoa With Love has a great article on Retain Cycles and how to avoid them. He gives 5 simple rules to avoid this situation:

  1. An Object Must never retain its parent – If a Parent Object is composed of a Child Object where the dealloc method releases the Child Object, the Child Object must not retain the Parent. Otherwise, the retain count of the Parent will never reach 0 and, thus, its dealloc will never be called releasing the Child Object.
  2. No Hierarchical Ancestor May be Retained – Know the ownership chain of your objects. Period.
  3. “Connection” Objects Should Not Retain Their Target – Buttons should never retain the Controller, for example.
  4. Use “Close” methods to Break Cycles – If there exists a retain cycle, write a custom method to clean up. This basically takes over for the dealloc method that you can manually execute.
  5. Temporary “retains” Must be Temporary – If you break any of the rules (which you will), do it temporarily and make sure it’s temporary.

The article is quite interesting and enlightening for how retain relationships are established.

Tagged with:
Jul 09

What would happen with the following code?

MyObject* myObj = [[MyObject alloc] init];

[myObj release];

[myObj method];

Hopefully, if you are lucky, your program will crash. But, it may not, nothing might happen. It may not crash immediately, but only have some other application writes to that memory location.

Therefore, it is typically considered good practice to set myObj to “nil”. This is because, calling a message on “nil” does nothing.

Also, this is safe to do in the scope of your application. Setting an object reference to nil only affects your local scope (essentially zeroing out the pointer), so if that object was retained elsewhere, calling nil will not affect it.

Tagged with:
Jul 09

Objective-C’s memory management uses allocation of memory and deallocation, similar to C’s malloc/free mechanism. Objective-C makes use of alloc/dealloc. However, it is more complex than that. Every NSObject has a “retain” count. Where alloc’ing sets the retain count to 1 for that object. What is interesting, is as a user you should never call “dealloc” directly. This is because Objective C will dealloc the object automatically when it’s retain count reaches 0. How would a retain count reach 0? When you are done with the object, you should call “release”.

This also means that if you are working on an instance of an object, you are responsible for managing its memory. I.e. you never know when that instance that was passed to you will have release called on it, causing your copy to be a invalid reference. So, if you have a method that takes an object and uses it for awhile (setting it to an instance variable, for example), you should retain it, and release it when you are finished.

You’ll see this paradigm used throughout the UI Toolkit. For example,

MyView *view = [[MyView alloc] initWithFrame:[window frame]];
[window addSubview:view];
[view release];

You’ll notice that as a client, I create a view and add it to a window view. That is the extent of what I need it for, so, therefore, release it. If the window’s addSubview method did not retain it, that view would be destroyed. Therefore, reading the documentation of NSView, you can see:

addSubview:
Adds a view to the receiver’s subviews so it’s displayed above its siblings.

- (void)addSubview:(NSView *)aView

Parameters
aView
The view to add to the receiver as a subview.

Discussion
This method also sets the receiver as the next responder of aView.

The receiver retains aView. If you use removeFromSuperview to remove aView from the view hierarchy, aView is released. If you want to keep using aView after removing it from the view hierarchy (if, for example, you are swapping through a number of views), you must retain it before invoking removeFromSuperview.

Emphasis is mine, but you’ll see that it is retained.

Tagged with:
preload preload preload