ObjectiveC: if (obj) {...} AND if (obj != nil) {...}, which is better? - objective-c

I've seen a lot of ObjC code which do:
obj = [[SomeObject alloc] init];
if (obj) {
/// ...
}
but as I understood it, the value inside () is a boolean, and 0 indicates FALSE 1 indicates TRUE(there is another case in other language that 0 is true and 1 is false), and if a pointer does not point to anything, it is set to NULL(nil), which is #defined to be 0, so I wonder is it better if I do:
if (obj != nil) {
/// ...
}
as it IS checking if the obj is nil or not, no matter what value nil is, so it does not rely on that nil (or NULL) happen to be defined as 0?

edit:
after testing a bit, I have determined that modern compilers will actually create the same machine code for both cases;
orig post:
It is (negligibly, perhaps) more efficient to use
if(obj) {
since you do not need to create the intermediary boolean value (by evaluating the comparison expression). I'm not sure which "other language" you are referring to regarding the non-zero being FALSE; the closest thing I can think of is c programs returning 0 for "success" and anything else for "error". Every modern language I have ever worked with uses 0 as FALSE and any non zero value for TRUE.
In Objective-C, nil is literally 0 (treated like a pointer). It is not just a pointer to zero, it is zero as a pointer. It is therefore reliably equivalent to FALSE (or, in our nomenclature "NO").
edit
after testing a bit, I have determined that modern compilers will actually create the same machine code for both cases; probably because nil is essentiall typedef'd to 0, so it knows the two styles of checking are both saying "if this pointer is non-zero".

0 indicates FALSE 1 indicates TRUE
Close. In C (and Objective-C), a 0 evaluates to false, and a non-zero evaluates to true. So a nil (or NULL) pointer is "false", but any non-nil pointer is "true".
Your examples are essentially equivalent; neither is "better" than the other (unless you or your codebase has a style preference).

Related

What is the rationale behind Apple's pattern of checking return value rather than error?

Apple's guide on Using and Creating Error Objects gives the following code example:
NSError *theError;
BOOL success = [myDoc writeToURL:[self docURL] ofType:#"html" error:&theError];
if (success == NO) {
// Maybe try to determine cause of error and recover first.
NSAlert *theAlert = [NSAlert alertWithError:theError];
[theAlert runModal]; // Ignore return value.
}
and accompanies it with the statement:
Important: Success or failure is indicated by the return value of the method. Although Cocoa methods that indirectly return error objects in the Cocoa error domain are guaranteed to return such objects if the method indicates failure by directly returning nil or NO, you should always check that the return value is nil or NO before attempting to do anything with the NSError object.
I have always been wondering why is this pattern so important? Why should we ALWAYS check the return value? What's wrong if we check whether the error is nil or not?
This design is not terribly unusual, compare also errno in standard C.
The design has a number of potential advantages:
The function does not have to write through a pointer on success. This does not only make the implementation of such functions easier and less error prone, it can also be a small performance advantage (e.g. this prevent CPU caches from being invalidated if the function succeeds).
If we always check that the function failed before accessing an error, we can use that same error pointer for multiple functions. Otherwise, we might get a previous failure rather than the failure of the most recent function.
This makes validation code easier to write. E.g. a function could set the error by default. If all validations pass, the function can simply return success instead of having to reset the error variable.
A function can use the same error pointer when calling other functions, but a failure of these helpers doesn't necessarily imply a failure of the top function.
In your specific case, the variable NSError *theError; has not been initialized. Accessing that variable without assigning to it first would invoke undefined behaviour. The documentation only guarantees that the variable will be set in case of an error.
Imagine you implement a method in terms of a few other methods:
-(BOOL)sendCachedRequestReturningError: (NSError**)err {
BOOL success = [self readCachedRequestReturningError:err];
if (!success && (*err).domain == MYFileDomain && (*err).errorCode == MYFileNotFoundCode) {
success = [self sendUncachedRequestReturningError:err];
}
return success;
}
Now there are 4 code paths here:
There is a cached request. We'll just return success == YES and all is good.
A non-recoverable error occurs trying to read from the cache. readCachedRequestReturningError: will set err and set success == NO and the caller will call presentError: or whatever
An error occurs trying to do the network request. Same as #2, err is set, and success == NO.
There is no cache, but we can make a network request. readCachedRequestReturningError: will set err to a valid NSError{MYFileDomain, MYFileNotFoundCode}, but then sendUncachedRequestReturningError: will succeed and set success == YES, and not touch err at all, leaving the previous error in it. If you now check err instead of checking the return value, you will think there was an error when all went well.
Note: The code above is grossly simplified, because we only care about errors. Of course in a real program, the methods would probably have another return parameter for the actual reply from the request, or would return the reply or nil instead of a success BOOL. It would also probably check whether err is NULL.

Kotlin let versus != null

What is the difference between using kotlin's object?.let {...} versus if(object != null) {...}? I've run into the situation where using let on a non-null equates to false and the block is not executed but using the if statement with the same object results in properly identifying that the object non-null and the block is executed.
Do they differ on the low level somehow?
Under the hood, object?.let { } will be compiled to if (object != null) { }. You can try to check the kotlin bytecode.
IMHO, using let also may benefit you to chaining function which makes your code declarative, and I think it is more readable.
One of the scenario where let keyword is preferable when you are reading the list of items that also contains null values and you wants to print only not-null values.
For Example:-
var array = arrayOf("StackOverflow", "Kotlin", "Android", null, "Jetpack", null)
for (item in array) {
item?.let {
print("$it ")
}
}
Output:
StackOverflow Kotlin Android Jetpack
Code inside for loop is like saying "if item is not null, let's print its value". Therefore ?.let allows you to run code for a value that's not null.

Decoding with NSCoding: Does Value Exist For Key?

When using NSCoding and decoding values, is there a way to tell if a value exists for a given key? In other words, what I'm trying to do is...
if([decoder valueExistsForKey:#"myKey"]) //valueExistsForKey is not a real method :(
{
NSInteger *myInt = [decoder decodeValueForKey:#"myKey"];
}
else
{
//handle special case
}
The issue is that I have old versions of documents in my app that don't have the "myKey" value, and if they don't have it, using 0 for myInt (what happens if you decode a nonexistent key) is not the behavior I want. However, I can't just decode and check if myInt == 0, because it might legitimately be equal to 0.
Since the valueExistsForKey method does not seem to exist, how can I replicate this behavior?
How about containsValueForKey?

the return value of a UIInterfaceOrientation object is equal to a boolean var?

This is a rather basic question regarding the return value from a simple UIInterfaceOrientation object, I try this code:
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
BOOL orientacion = interfaceOrientation;
return orientacion;
}
and the conversion does it, so I thought a UIInterfaceOrientation object is equal to a boolean var?? is that a implicit typo or really UIInterfaceOrientation is equal to a boolean value..
UIInterfaceOrientation is an enum, which essentially means it's an integer. Integers can be assigned to booleans. Many things can--booleans simply equate to true or false. If a boolean is set equal to 0 or nil, it is false. If it is set to anything other than 0 or nil (or some other #defined equivalent) it will be true. Since UIInterfaceOrientation is an enum (an integer), if it is equal to 0 the boolean will be false. If it is anything but 0 it will be true.
The values of UIInterfaceOrientation:
typedef enum {
UIDeviceOrientationUnknown,
UIDeviceOrientationPortrait, // Device oriented vertically, home button on the bottom
UIDeviceOrientationPortraitUpsideDown, // Device oriented vertically, home button on the top
UIDeviceOrientationLandscapeLeft, // Device oriented horizontally, home button on the right
UIDeviceOrientationLandscapeRight, // Device oriented horizontally, home button on the left
UIDeviceOrientationFaceUp, // Device oriented flat, face up
UIDeviceOrientationFaceDown // Device oriented flat, face down
} UIDeviceOrientation;
The first on this list will equal 0. The next 1, the next 2, etc. So UIDeviceOrientationUnknown will set the boolean to false; anything else will set it to true.
In any case, you're not using this function correctly. The code inside this function needs to read:
if((interfaceOrientation == someOrientationYouWantToWork) || (interfaceOrientation == someOtherOrientationYouWantToWork)
{
return YES;
}
else
{
return NO;
}
Set someOrientationYouWantToWork etc to values from the enums I posted above. Whichever orientations you want to work, return YES for. Else it will return NO.
It's not a boolean value, but an enumerated value - if it's anything other than 0, it's defaulted to the boolean "YES", otherwise it's "NO".

Sending isEqual: to nil always returns NO

If you send isEqual: to an object that happens to be nil, you always get NO back.
Is this the expected behavior? To be a feature instead of a bug, I would expect it to return YES if the other object is also nil, and NO otherwise? Semantically this seems the correct behavior.
In case my expectations are incorrect, what the recommended proceedure? Check for nil before sending isEqual: (and friends)?
Yes, this is the expected behavior. Any message to nil will return a result which is the equivalent to 0 for the type requested. Since the 0 for a boolean is NO, that is the result.
This is expected behaviour from Objective-C. This basically means that doing this
if ([nil isEqual:nil]) { ... }
evaluates to NO. Even though it doesn't make sense, when looking at it - and even though it's annoying - being able to send messages to nil is actually one of the really cool things about Objective-C. Saves you a lot of code sometimes.
My solution is to define this macro somewhere handy
#define IsEqual(x,y) ((x && [x isEqual:y]) || (!x && !y))
So when I need to test if two objects are equal:
if (IsEqual(obj1, obj2)) { ... }
or not equal:
if (!IsEqual(obj1, obj2)) { ... }
Hope this helps.
It is expected, for two reasons: (1) in Objective-C, sending a message to nil always returns a false-y value (nil, NO, 0, 0.0, etc.; or, more generally speaking, 0, which can be interpreted based on the expected return type of the method); (2) nil represents an unknown value, and two unknown values are not necessarily equal to each other.
If you want to see if an object is nil, use if (!obj) or if (obj == nil).