I'm doing a check in an iPhone application -
int var;
if (var != nil)
It works, but in X-Code this is generating a warning "comparison between pointer and integer." How do I fix it?
I come from the Java world, where I'm pretty sure the above statement would fail on compliation.
Primitives can't be nil. nil is reserved for pointers to Objective-C objects. nil is technically a pointer type, and mixing pointers and integers will without a cast will almost always result in a compiler warning, with one exception: it's perfectly ok to implicitly convert the integer 0 to a pointer without a cast.
If you want to distinguish between 0 and "no value", use the NSNumber class:
NSNumber *num = [NSNumber numberWithInt:0];
if(num == nil) // compare against nil
; // do one thing
else if([num intValue] == 0) // compare against 0
; // do another thing
if (var) {
...
}
Welcome to the wonderful world of C. Any value not equal to the integer 0 or a null pointer is true.
But you have a bug: ints cannot be null. They're value types just like in Java.
If you want to "box" the integer, then you need to ask it for its address:
int can_never_be_null = 42; // int in Java
int *can_be_null = &can_never_be_null; // Integer in Java
*can_be_null = 0; // Integer.set or whatever
can_be_null = 0; // This is setting "the box" to null,
// NOT setting the integer value
Related
Converting a String to Int returns an optional value but converting a Double to Int does not return an optional value. Why is that? I wanted to check if a double value is bigger than maximum Int value, but because converting function does not return an optional value, I am not be able to check by using optional binding.
var stringNumber: String = "555"
var intValue = Int(stringNumber) // returns optional(555)
var doubleNumber: Double = 555
var fromDoubleToInt = Int(doubleNumber) // returns 555
So if I try to convert a double number bigger than maximum Integer, it crashes instead of returning nil.
var doubleNumber: Double = 55555555555555555555
var fromDoubleToInt = Int(doubleNumber) // Crashes here
I know that there's another way to check if a double number is bigger than maximum Integer value, but I'm curious as why it's happening this way.
If we consider that for most doubles, a conversion to Int simply means dropping the decimal part:
let pieInt = Int(3.14159) // 3
Then the only case in which the Int(Double) constructor returns nil is in the case of an overflow.
With strings, converting to Int returns an optional, because generally, strings, such as "Hello world!" cannot be represented as an Int in a way that universally makes sense. So we return nil in the case that the string cannot be represented as an integer. This includes, by the way, values that can be perfectly represented as doubles or floats:
Consider:
let iPi = Int("3.14159")
let dPi = Double("3.14159")
In this case, iPi is nil while dPi is 3.14159. Why? Because "3.14159" doesn't have a valid Int representation.
But meanwhile, when we use the Int constructor which takes a Double and returns non-optional, we get a value.
So, if that constructor is changed to return an optional, why would it return 3 for 3.14159 instead of nil? 3.14159 can't be represented as an integer.
But if you want a method that returns an optional Int, returning nil when the Double would overflow, you can just write that method.
extension Double {
func toInt() -> Int? {
let minInt = Double(Int.min)
let maxInt = Double(Int.max)
guard case minInt ... maxInt = self else {
return nil
}
return Int(self)
}
}
let a = 3.14159.toInt() // returns 3
let b = 555555555555555555555.5.toInt() // returns nil
Failable initializers and methods with Optional return types are designed for scenarios where you, the programmer, can't know whether a parameter value will cause failure, or where verifying that an operation will succeed is equivalent to performing the operation:
let intFromString = Int(someString)
let valueFromDict = dict[someKey]
Parsing an integer from a string requires checking the string for numeric/non-numeric characters, so the check is the same as the work. Likewise, checking a dictionary for the existence of a key is the same as looking up the value for the key.
By contrast, certain operations are things where you, the programmer, need to verify upfront that your parameters or preconditions meet expectations:
let foo = someArray[index]
let bar = UInt32(someUInt64)
let baz: UInt = someUInt - anotherUInt
You can — and in most cases should — test at runtime whether index < someArray.count and someUInt64 < UInt32.max and someUInt > anotherUInt. These assumptions are fundamental to working with those kinds of types. On the one hand, you really want to design around them from the start. On the other, you don't want every bit of math you do to be peppered with Optional unwrapping — that's why we have types whose axioms are stated upfront.
I was thinking how this "Powerful Solution" according to apple of the Optional Variables is actually powerful if it's something that we already had in Obj-c?
var mystring: String? = nil
if mystring {
//string is not nil
}
Second Scenario won't compile
var mystring: String = nil
if mystring {
//string is not nil
}
We were able to do this in Obj-C before without any additional set up.
NSString * somestring = #"Test";
if(something != [NSNull null]){
//Do something.
}
or
NSString * anotherstring = nil;
if(anotherstring == [NSNull null]){
//display error.
}
so I am really confused on how this is that powerful as they claim if it already existed in a former language.
Some info about Optional Variables
The optional is a type on its own (actually an enum), and it can hold 2 values:
an actual instance/value of the type the optional is used for (corresponding to the Some enum case)
a nil value (corresponding to the None enum case), which represent the absence of value
The difference with other languages like ObjectiveC is that optionals don't use a valid type value, which can have a meaning in some cases and a different meaning in others.
In objective C, the absence of a reference type is represented by nil, which is actually a pointer to the location 0x00000000 (in a 32 bits scenario).
The absence of a value type instead is usually by convention. A function returning an integer can define -1 as absence of value, but -1 is an integer itself, and if the function can return negative values it cannot be used.
In Swift instead an optional can have either a valid integer value, or None, which is not itself an integer (nor an instance of a class, a struct, or whatever type is used with the optional).
Also, more important, you cannot assign nil to a non optional variable - that results in a compilation error, hence preventing a lot of common bugs that usually are discovered at runtime, and frequently hard to track down.
Last, whereas in objective C you can use nil for reference types, you cannot use for value type (as mentioned above for the integer type). In swift instead an optional can be nil regardless of the contained type - so a Int? can be either an integer or nil.
Swift optionals let you make it explicit whether a variable can be nil, whereas Objective-C is all for guessing games. Less nightmares about EXC_BAD_ACCESS errors. That's where the power lies.
In Objective-C a pointer to an object could be nil, yes. But there was no enforcement about if nil made sense.
NSString *shouldNeverBeNil = #"a string!";
shouldNeverBeNil = nil;
NSLog("Hello, %#", shouldNeverBeNil); // "Hello, "
In ObjC this compiles fine though we should never say hello to nothing. That's a bug.
But if we do the same in Swift it doesn't even compile and we don't get a runtime bug at all.
var shouldNeverBeNil: String = "a string!"
shouldNeverBeNil = nil; // Compilation error.
NSLog("Hello, %#", shouldNeverBeNil); // never happens
Optionals allow you to bless variables with the ability to be nil. Compilation errors are always preferable to runtime errors since it's impossible for an end user of your app to run into a compilation error.
If you want to allow that value to be nil Swift makes you bless it explicitly, as an Optional. Now if it's nil, you explicitly allowed it and Swift reminds you to handle handle both the nil case and the value case in your code.
var okToBeNil: String? = "a string!"
okToBeNil = nil;
if okToBeNil != nil {
NSLog("Hello, %#", okToBeNil!); // never happens
} else {
NSLog("What is your name?")
}
In objC,
NSString *stringValue = #"123s";
NSInteger *intValue = [stringValue integerValue];
NSLog(#"intergerValue %#",intValue);
if(!intValue)
{
NSLog(#"caught null object");
}
else
{
// Do appropriate operation with the not null object
}
prints " interValue (null) "
" caught null object "
and the binding is done safely by using !(not) operator inside if condition...
But whereas, in swift the equivalent snippet using optional variable is
var normalValue : String = "123s"
var optionalValue = normalValue.toInt()
println("optionvalue \(optionalValue)")
if optionalValue {
// Do appropriate operation with the not nil value
}
else{
println("caught null object")
}
this "optional binding" is done in objectiveC also, then what is the exact use of having optional variable/constant. And it's also been said that we can avoid returning null object instead we can return nil value. What is the problem when we return a null object, does it cause performance issues?
Your valid thoughts....
The intention behind optional types was to let programmers make variables that might not have a value. It was the default model in Objective-C, it has been reversed in Swift, because the language requires variables to have a value by default.
Objective-C refers to all objects through pointers (hence the asterisk * after the type name). Since all pointers are allowed to have no value (i.e. nil) one could think of all Objective-C objects as optional, i.e. the corresponding variable may have no value at all.
Since Swift does not have a requirement of C compatibility on the source code level, language designers choose to require objects to have a value of the specified type, and provided support for making variables that may not have a value through optional types.
I am getting a object value from server as null value when NSlog this object.I want to identify it in if-else decision statement. How can I check it because nil have reference to a unknown object which not means NULL.and i can't compare it with zero too.
How can i identify that this value is NULL, i have a crash on this point.I have tried #try - #catch block too but all gone in vain.
Any suggestion for this problem.
As others have pointed out, there are many kinds of "null" under Cocoa/Objective C.
But one further thing to note is that [object isKindOfClass:[NSNull class]] is pointlessly complex since [NSNull null] is documented to be a singleton so you can just check for pointer equality. See Topics for Cocoa: Using Null
So use this :-
if (title == (id)[NSNull null] || title.length == 0 ) title = #"Something";
Note how you can use the fact that even if title is nil, title.length will return 0/nil/false, ie 0 in this case, so you do not have to special case it. This is something that people who are new to Objective C have trouble getting used to, especially coming form other languages where messages/method calls to nil crash.
If you want in detail what is the difference between nil, Nil and null, you can check this article What is the difference between nil, Nil and null.
You can try following code to check for NULL values from server:
if (nil == str || NSNull.null == (id)str) {
//Object has Null value
}
else{
// Object has some value
}
str is string value which contain server value.
This may helps you.
The Best Approach is :
if([yourObject isKindOfClass:[NSNull null]])
{
// yourObject is null.
}
else
{
// yourObject is not null.
}
A seemingly simple question: Can I have some sort of Number object, which can be nil but which I can assign like a primitive int:
like this:
NSNumber *n = nil;
n = 3;
if(n == nil){
// some actions...
} else if (n == 1){
// some actions...
} else {
// some actions...
}
Thanks for your input
The answer is NO. If the variable is an object you can either assign another object,
n = anotherNSNumber;
or, set the value by using properties or by methods,
n = [NSNumber numberWithInt:3];
and, compare the object with another object,
if (n == anotherNSNumber) // Checks the reference
or compare its value by using properties/methods,
if (([n intValue] == 3) || ([n intValue] == [anotherNSNumber intValue]))
The short answer as others have mentioned is "No".
But the following slight modification to you code will achieve a similar result:
NSNumber *nObject = [NSNumber numberWithInt:3];
int n = nObject.intValue; // Zero if nObject is nil
if(nObject == nil){
// some actions...
} else if (n == 1){
// some actions...
} else {
// some actions...
}
Not the way you think you can. No.
when you say:
NSNumber *n = nil;
what you are saying is declare a pointer that points to an NSNumber object, but for now have it point to nil This is okay; because what you might do later is to get a pointer to an NSNumber object and then assign it to this variable so that n is then a pointer no a valid NSNumber object.
With your next line:
n = 3;
You are not assigning a value to the object, but you are saying that n points to the address 3. Which isn't an address and which doesn't contain an object.
No, you can't. The reason for that is that nil is a pointer to the address 0x0 i.e. nil == 0. So you won't be able to disambiguate between 0 and nil.
Not to mention the fact they are also supposed to be different types. nil is used as a pointer whereas a number like 0 or 3 is a scalar.
nil is defined as
#define nil NULL
A typical definition of NULL goes like this:
#define NULL ((void *)0)