views:

368

answers:

5

Two parts to this question

1) Is this understanding of what's going on correct?
"if (obj)" is testing to see if the pointer is not 0x0, aka set to an integer memory address
"if (obj != nil)" is comparing the memory address of the object to the memory address of the universal nil object

2) So in a situation where I don't know if a variable is pointing to anything, and if it is, I also don't know if that object is a valid object or nil. I want to do a variety of things based on that information, not just pass a message to obj, which I realize would be safe if it's nil. Is this code both correct and necessary?

if (obj && obj != nil) {
    // Do a bunch of things that should only happen if obj is pointing to a valid object
    [obj someMessage];
    [anotherObj someOtherMessage];
}

Thanks guys!

+11  A: 

This is correct, in the sense that it will give you the result you expect, but redundant. It's sufficient to just use:

if (obj) {

or

if (obj != nil) {
Ben Gottlieb
Thanks a lot for the answer. Upvoted for correctness, but I'm going to mark Ben's as the answer for explaining the reasoning behind it.
DougW
A: 

if (obj == nil) then if (obj) will evaluate false. You don't need both.

Nick
Sorry for the downvote, I really did not mean to downvote this one, as I clicked on Uk Viagra's answer. I can't un-vote since it has been for too long, but I will un-vote when you edit your post.
JoostK
+14  A: 

Correct? Yes. Necessary? No. Objective-C simply #defines nil to (void *)0, which is, in C terms, false. So simply writing

if (obj) {
    [obj someMessage];
    [anotherObj someOtherMessage];
}

is sufficient. Further, since Objective-C has message-eating nil, you can simply omit the check in some circumstances. (E.g., if the second line were not there in the if block, you could simply call [obj someMessage] indiscriminately.)

Benjamin Pollack
How do you `typedef` a value? ;)
Pavel Minaev
Whoops. Fixed. Thanks, Pavel.
Benjamin Pollack
Some of the other answers seem correct, but I think this one does the best job of explaining what's going on.
DougW
+4  A: 

You can simply use if (obj). According to objc.h, nil is a #define for __DARWIN_NULL. Poking around in /usr/include/sys/_types.h, we see that __DARWIN_NULL is defined as 0L, 0, or (void *)0, depending upon platform and whether you're using a C or C++ compiler. But in the end, nil always evaluates to false, so the simpler if (obj) will suffice.

mipadi
+4  A: 

Not a direct answer to your question, but to the question sort of implied by part 2: There is no way to tell whether a pointer references a "valid object" aside from sending a message and seeing if it does what you want. There are all kinds of things that aren't nil but still aren't what would be considered a "valid object" for most purposes. For example, an object variable might point to:

  • The garbage space where a deallocated object used to live
  • A new object that's been allocated in place of the object the variable is supposed to point to
  • An int that you accidentally set the variable to
  • A C string that you accidentally set the variable to instead of an NSString

There's no way to test at runtime if any of these are the case. You have to make sure your code is free of bugs that would put a variable into a state like that.

Chuck
While developing, you can in XCode turn on the setting NSZombieEnabled. In some way this creates instances of NSZombie in all invalid pointer locations, and an NSZombie will only throw an exception or give some other major error indication for all messages you send to them. See this question: http://stackoverflow.com/questions/535060/how-to-add-nsdebug-h-and-use-nszombie-in-iphone-sdk
harms
Clarification: NSZombieEnabled does help to track down these sorts of bugs, but it doesn't create NSZombie instances at "all invalid pointer locations." It makes `dealloc` turn objects into NSZombies instead of actually deallocating them. You still won't get zombie exceptions when a pointer is set to an address that never was an object, like the int or C string examples I mentioned in my answer.
Chuck
Sure there is. For my purposes "valid object" means "instance of object". You can use [obj isKindOfClass:[ObjClass class]], and if it's nil that will be false. I just thought there might be a shortcut with obj != nil. In my case, I know the variable will always be either uninitialized, nil, or instance of class X.
DougW
Although I guess that would be considered "sending it a message", so yes you're correct, there is no way to tell from the pointer alone. Upvoted.
DougW