Feb 12

It is a good practice to set a variable to nil after you release it:

[myVariable release], myVariable = nil;

If you don’t do this then you may experience bugs that are difficult to track down. Say that you inadvertently refer to myVariable after it has been released. Sometimes the memory pointed to by myVariable still has the old content of your object, and your app will run fine. Sometimes that memory location has been overwritten with something else, and you’ll get an unpredictable result.

One nice characteristic of Objective-C is that you can send messages to nil objects without error. (Unlike Java, for example, where NullPointerException is probably the most common exception thrown.) So if you have set myVaraible to nil and you then try to send a message to it with [myVariable something] then it will not fail. Nothing will happen of course, but at lest nothing will happen every time, which is much easier to track down than indeterministic behavior.

One might argue that sending a message to a nil object is the result of faulty code. Your code should know if an object is valid or nil. But here’s a simple counter-example:
If your class has properties with a retain declaration, then you should release those properties in the dealloc method. In many cases setting the value of a property to nil is perfectly valid. And thus sending release to that nil property in dealloc should be ok.

Keep in mind that the above conventions apply to Objective-C. If you’re calling Core Foundation functions you need to be more careful when dealing with nil.

For example, if you call the following function with a nil parameter, it will fail:

CFRelease(contactFirstName);

Before calling CFRelease you need to check the parameter value like this:

if (contactFirstName) CFRelease(contactFirstName);

written by Nick \\ tags: , ,

7 Responses to “Memory Management and nil”

  1. Mark Lorenz Says:

    Respectfully, I have to disagree with you on setting object pointers to nil after calling release.

    Since Objective-C uses a reference counting system to keep track of memory, it’s very easy to see how the following scenario could play-out:
    1) objectOne creates an NSString (i.e. NSString* fooString = [[NSString alloc] init];)

    2) objectTwo is passed fooString, and calls [fooString retain]; because it’s using the string, and needs it around.

    3) objectOne is done with fooString, and so calls [fooString release]; Now, by your suggestion, it also does fooString = nil;

    4) objectTwo tries to do an operation on fooString, but since objectOne set it to nil, the operation fails, and SILENTLY (because as you state, messages to nil are perfectly valid). Now you have no idea why objectTwo isn’t working correctly, and worse fooString may be been set to nil some time earlier, maybe even several run loops earlier, so it will be very difficult to figure out what’s going wrong. It can also be extremely difficult to figure out what object is setting fooString to nil in the first place.

    In a reference counting memory management system, it’s much smarter to let the run time do it’s job, and keep track of those references. If a fully released object is called you know immediately why the crash occurred, and then you just need to figure out where your reference counting went wrong.

    One more thing, often times when a memory mis-management crash occurs the debugger will show objects you thought were one type as a different type entirely. For example, something you though was a UIImage will show as an NSString in the debugger. For this same reason it’s also common to get “Object Does Not Recognize Selector” crashes, becuase your sending UIImage methods to an NSString (again, for example).

    I hope you can see my point of view as a better choice than setting variables to nil.

  2. Geoffrey Foster Says:

    Mark, I respectfully disagree with you. You’re actually wrong in the scenario that you described.

    1) objectOne creates an NSString via [[NSString alloc] init]. This NSString object now has a retain count of 1
    2) objectTwo is passed the NSString* and calls retain on it, the NSString object now has a retain count of 2
    3) objectOne is done with the NSString and calls release on it, the NSString object now has a retain count of 1. Setting the NSString* to nil is perfectly safe here
    4) objectTwo tries to do an operation on the string, which still has a retain count of 1, thus this is perfectly okay.

  3. Trevor Says:

    @Mark: “objectTwo tries to do an operation on fooString, but since objectOne set it to nil…”

    Wrong. You’re confused about pointer copies. When objectOne passed fooString to objectTwo, it passed a *copy* of the fooString pointer. At this point objectOne has a copy of the fooString pointer, and objectTwo has its own distinct copy of the fooString pointer as well. Therefore, when objectOne sets its copy to nil, there is no effect on objectTwo’s copy.

  4. Mark Lorenz Says:

    @Geoffrey and @Trevor. You are both correct. Thanks for pointing that out.

    I do still stand by my statement that it’s generally preferable to crash rather than silently message nil. Unless your program is setup in such a way that messages to nil are part of the program logic.

  5. sahrp mind Says:

    will these pointers be handled like c++

  6. Abhinav Says:

    setting foostring to nil basically means setting the pointer as nil

    We should not get confused that the object to which foostring pointed is still in memory.
    we have just lost the reference to obj1 by setting as nil and since its refcount was 2 after obj2’s retain, and refcount of foostring is 1 after calling the release and setting it as nil.
    Although if the code is upto this only, i doubt that the object allocated actually still have a refcount 1. and we have set the obj1 to nil so we have actually lost its reference and cant further send release to reduce refcount to zero.

    Isn’t it a leek in that case.
    However we are nt discussing leak here but i doubted it.
    What are your comments to that.

  7. Nick Says:

    @Abhinav: Setting a pointer to nil does not change the reference count and does nothing for memory management. The reason for setting pointers to nil after you have released the object the pointer points to is to avoid you trying to access that object via the pointer later in your code. If there are no other references to that object it will be released and the memory location for the object will be reclaimed. If you did not set your pointer to nil it will still point to the same memory location, which now may contain a very different object. This can lead to some confusing errors at runtime.

    Of course you should not write code that tries to access objects that you have released. So in a perfect world, setting a pointer to nil after you release the object is not necessary. But being an imperfect programmer, I find it to be a useful failsafe mechanism and one that does not require a lot of effort.

Leave a Reply