views:

3448

answers:

5

So I thought I had all these questions all figured out. Then all of a sudden i get an error (a crash) i can't figure out. THen after doing research to remedy the crash, i notice everything that I thought i knew about these critical areas are somewhat wrong.

Below are 8 questions im just going to shoot out there in hopes of somebody answering - the answers to these will greatly help me get my understanding back on track. Thanks ahead of time!

Q1) Is it okay to call Release on an object if that reference is nil? This should be harmless, right?

Q2) Is it okay to call Release on an object if that reference has been released and as a reference count of 0?

Q3) Is it necessary to set a reference to nil AFTER releasing it? What happens if you dont set it to nil?

Q4) Is there really a difference between nil and NULL, or is it just a semantic thing to help the reader/developer know the object type just by glancing at it?

Q5) Using properties REQUIRE the use of the 'Self' pointer?

Q6) Using instance variables requires that the 'Self' pointer is NOT used?

Q7) When would i ever want to use an instance variable instead of its property? I'd imagine value type data members are okay since their is not releasing and retaining involved.

Q8) Is it necessary to call an object's dealloc from within the dealloc function? In many examples i've seen Release being called, but not Dealloc - are such tutorials incorrect?

+7  A: 

You should probably have split this question up into multiple different questions, but I'll bite.

  1. Yes, any message sent to nil is a no-op.
  2. No. An object with a ref-count of 0 has been, or imminently will be destroyed and any messages sent to it will cause a crash, or at best, an exception.
  3. It depends on the situation. If you're releasing things in -dealloc, then probably not. If it's an object that is scoped to a particular method, then probably not. If it's an ivar that is reused, I'd say yes. In the first two cases, nothing will happen if you don't set the pointers to nil, since you usually won't be able to access those pointers anymore. In the last case though, you still can access the pointer, which is pointing to deallocated memory. If you send it a message or try to dereference it, your app will crash.
  4. They are both equal to 0. By convention nil is used for object pointers, and NULL is used for any other pointers, but mixing them won't cause any problems.
  5. If you want to invoke the property getter/setter, then yes. If you want to access the ivar it encapsulates directly (uncommon), no.
  6. No, you can access instance variables using the syntax self->ivar. In fact, when you type just ivar, the compiler implicitly adds the self-> dereferencing.
  7. Not sure what you mean here.
  8. The only time you should be calling -dealloc is when calling [super dealloc]; in your own -dealloc methods. For any other objects you should always just call -release.
kperryua
At (2) NSZombieEnabled should be mentioned. It makes debugging alloc problems easy.
diciu
"easy" is a strong word! I would say "easier".
TandemAdam
+9  A: 

A1) [nil release] is fine (won't do anything)

A2) No. Don't touch objects after they've been deallocated. They should be set to nil after they are released.

A3) It's not necessary to set a released pointer to nil, but you get dangling pointers (i.e., you can't tell if an object is valid or not). Setting a property to nil is often used to release the underlying ivar, so failing to do this can cause a memory leak

A4) nil and NULL are both zero, so are technically the same.

A5) Yes, you must use self.someProperty for properties, just as you would use [self someProperty] if it was just a method

A6) self is essentially a struct, so you can access ivars like so: self->someIvar. There is no need to, though.

A7) When you don't want to run the setter/getter methods for whatever reason. I use it ocassionally when the setter doesn't allow nil values, and I need to release the variable

A8) dealloc is called automatically when release is called the correct amount of times. You should never call dealloc directly (except for [super dealloc])

Tom Dalling
I'm confused about #5. I have a nonatmic, retained @property called "social" in a view controller and these statements log the same thing: NSLog(@"%@", social); and NSLog(@"%@", self.social); Can you explain, Tom?
Typeoneerror
That's because both `NSLog` statements are printing the same object. The difference is that `self.social` calls a method that returns the object, and `social` is just the object itself.
Tom Dalling
+2  A: 

Others have answered 1-6 adequately.

(7) Apple recommends you use the instance variable directly in both your init and dealloc. Primarily this is because the object (especially if it is subclassed) is only partially set up during both of these methods, and so calling setters/getters may result in incorrect behavior if they have anything other than trivial actions. Generally you can safely access the ivar directly (rather than via the getter) in your object, and it will be marginally more effecient to do so (only relevent on the iPhone). Generally you should use the setter in all cases, especially if your object may be subclassed or if others may be observing the property.

(8) You never, ever, call dealloc (except [super dealloc] from within the dealloc method). If you have an ownership on another object, then you should relinquish that ownership (by calling release or autorelease). The system will then call dealloc on the object if appropriate. But you never call dealloc yourself. Read the memory management rules (its only 9 paragraphs and is vital to understand).

Peter N Lewis
thanks. i found the link to the MM rules somewhere that somebody pointed out. ill be reading it definitely.
Edward An
Btw, all these questions came about when my idea of releasing and nil's was shattered after an unexpected crash (app crashes after i set a reference to nil). Why on earth would assigning a pointer to nil crash the app?Since then i've been using 'self' every place where i assign a pointer to another reference.
Edward An
The only reason setting a reference to nil would crash would be if the reference was part of an invalid or dealloced object. Enable NSZombies and perhaps that will help.
Peter N Lewis
Peter N Lewis
A: 

Ok. It is official. I absolutely do not understand memory management anymore. :(

All I am trying to do is Release a navigation controller. I start off with a view A. Then I navigate to view B. From B I navigate back to A.

Then in A's viewWillAppear method I do this:

[A release];

A = nil; // This is where my app crashes!.

So, now this begs the obvious question, why would setting A to nil crash the entire app?

Edward An
Maybe some other code you have hadn't finished using A.
Jorge Israel Peña
Uh, so... you're trying to release a view controller while inside its viewWillAppear method? No offense, but you're doing something very very wrong.If you actually want a quality answer for this particular problem, you should create a new question and add as many details as you can, with code if possible. This is going outside the scope of your original question.
Mike McMaster
Ok, thanks for the help. But allow me to reply to this before i start a new thread, precise thread.I am calling [B release] from within A. But you made a point that perhaps B isn't finished yet when i release and set to nil. So, i will see what i can do to make sure B is done in use. Thanks!
Edward An
Damn. I mean to say [B release] in the original comment, not A!!
Edward An
A: 

Ok. I have confirmed that not setting B to nil did the trick. So, now, i dont check for nil when creating the B controller (when i want to navigate to it).

Instead, i release B, then i create the controller and assign it to B. Then, in A's viewDidAppear method, i release B.

I believe this thread is now closed. Thanks!

Edward An