Comparing two NSNumbers using isEqualToNumber method - ios

While I compare two NSNumbers using isEqualToNumber, it is returning a false if both numbers are nil. Why a comparison of sort [nil isEqual:nil] always returns false while nil == nil returns true ?

It is the standard behaviour. You will get the same result from isEqueslToString: etc. It is better this way, because you could have for example weak references to unequal objects, which would become equal uppon deallocation.
You can use a condition like number1.intValue == number2.intValue in which case it would return YES for 2 nil objects. However, you will also get YES for nil.intValue == #0.intValue

[nil isEqual:nil] compares objects while nil == nil compares pointers.
Pointer to nil is always equal to pointer to nil. On the other hand object that does not exist is not equal to anything.

Related

collectionView.indexPathsForSelectedItems.contains(x)

I am trying to run collectionView.selectItem(at: indexPath, animated: false, scrollPosition: []) if if(!collectionView.indexPathsForSelectedItems?.contains(x)) returns true. But I can't seem to get it to work.
I thought it had something to do with optionals, but it doesn't seem to.
I have tried if let, ? ?? ! etc. I have created an optional index_path object and still cannot get it to work.
You can't have an optional Bool? as the only member of an if condition. That's because the compiler (with good reason) refuses to infer what it must do when it gets a nil value.
You have several ways to solve this, the important thing is: make sure you're handling the nil case the way you intend it to.
From a quick look at the documentation we learn that indexPathsForSelectedItems returns nil if there are no selected items. In that case your condition must yield a true value, because when there are no selected items, x is most certainly not contained in the array of selected values.
So, a first solution might be to tell the compiler to treat a nil value from indexPathsForSelectedItems as an empty array, which seems quite reasonable: if there are no selected items the array that represents the selected items' indexPath should be empty:
// solution 1
if !(collectionView.indexPathsForSelectedItems ?? []).contains(x) {
// select item..
}
You have a second way to solve this if you consider that you can't have an optional Bool? inside an if condition, but you can always compare a Bool? with a Bool and thus explicitly tell the compiler the only case among the three you are interested in:
let isXSelected = collectionView.indexPathsForSelectedItems?.contains(x)
isXSelected returns nil → no items selected, i should select x
isXSelected returns true → nothing to do
isXSelected returns false → i should select x
You want to execute the "select x" code in both case 1 and 3, so you want to check if isXSelected is not true. In conclusion:
// solution 2
if collectionView.indexPathsForSelectedItems?.contains(x) != true {
// select item..
}
Result of
collectionView.indexPathsForSelectedItems?.contains(x)
is optional bool value: Bool?. Swift does not allow implicit cast to Bool type. To solve it, create unwrapping of optional array to non optional array indexPathsForSelectedItems :
if !(collectionView.indexPathsForSelectedItems?.contains(x) ?? false) {
//TODO:select item
}

Objective C - NSArray's indexOfObject: not work

I use [items indexOfObject:items.lastObject] to get the last index, but this code returns nil. Why does this happen?
The first and last object in your array are both bar button items created with the system item of "fixed space".
The result of calling indexOfObject: is 0, not nil. This means that the object is being found at index 0. indexOfObject: can't return nil. If an object isn't found, it returns the special value NSNotFound which is the unsigned value for -1.
From the documentation for indexOfObject::
Starting at index 0, each element of the array is passed as an argument to an isEqual: message sent to anObject until a match is found or the end of the array is reached. Objects are considered equal if isEqual: (declared in the NSObject protocol) returns YES.
The implementation of UIBarButtonItem isEqual: will return YES if two bar button item instances are created with the same system item (and probably a few other properties as well).
indexOfObject: is not based on the instance of the object, it's based on isEqual:.
If you want to find the index of an object based on the identity (its address) of the object instead of isEqual:, use indexOfObjectIdenticalTo:.
p [items indexOfObjectIdenticalTo:items.lastObject]
will give you 6 instead of 0.

How to check if view has tag?

Help me pls with this unexpected trouble.
if (view.tag != nil)
^^ this worked for me, but suddenly i've assigned 0 tag to the view, and now everything's broken.
How can i check if view has a tag assigned ?
Thanks
All views have a tag. default is Zero 0
It depend on what you have. I believe you should consider a view with tag 0 is a view that is not tagged. and start tagging from 1.
Since the tag property of a view is of type NSInteger it can not be nil. NSInteger is a primitive type and therefore can not have a nil pointer. The default value assigned to the property will be 0.
Also, when you compare nil with 0 it gives a YES in objective-c. Thats what is breaking your logic.
if (view.tag != nil) equivalent to if (view.tag != 0)
tag is non-negative value. if you don't set tag of a view then it's default tag is 0. so, you have always a tag associate with a view.
in this regards, if you set tag>0 then you can check
if(tag>0){
//do something
}else{
//this is not your view
}
But you can't check
if (view.tag != nil)// because nil compares with object and if that object not found then return nil. if you compare with it nil value with an integer number it will also return 0. you will get a unexpected result.
There are a couple of things to understand:
Tag is an unsigned integer, which is a primitive type, and nil is used to test for an unassigned object type.
The compiler will consider nil to be 0 in this context, which is the reason it doesn't "fire".
Solution:
Assign tag > 0.
Test using if (view.tag > 0) { ... }.

How to check if object is nil? [duplicate]

I am currently studying objective-c and the basic c programming language.
I have a questions about a particular line of code:
if (!balance)
Balance is an object that is created. I understand that this code is checking to see if the object balance is nil or not, is this correct?
Could somebody please explain how exactly the code checks for nil? Does it return 0 if the value of balance is nonzero and 1 if the value is 0?
Thanks in advance.
In Objective-C, nil is roughly analogous to 0, NULL or false, but for object pointers. In an if statement, it will behave the same as one of the aforementioned scalar values. For example, the following two if statements should produce the same results:
NSNumber *balance = nil;
if (!balance) {
// do something if balance is nil
}
if (balance == nil) {
// do something if balance is nil
}
NSLog should return (null) (which probably is description for nil), not NULL in console. Your check should look like this:
if (!controller)
{
// do some stuff here
}
If balance is nil then it will be a pointer to 0x0. That address is never used for a valid object.
In C anything within an if that evaluates to zero is considered a negative response, anything that evaluates to non-zero is a positive response.
Pointers evaluate to their address — exactly as if you cast them to an integral type. The ! means "NOT".
So the test is if(address of balance is not zero).
First you need to understand how if works. Basically, any non-zero value is treated as true and a zero value is treated as false.
Something as simple as if (10) will be treated as true while if (0) is treated as false.
Any expression evaluates to either a value of zero or a non-zero value.
An object pointer is just a number - a memory address. A nil pointer is simply an address of 0. Any non-nil pointer will have a non-zero address.
The ! operator negates that state. A non-zero value will be treated as a zero value and visa-versa.
So now combine all of this.
Foo *bar = nil;
if (bar) // false since bar is nil (or zero)
Foo *bar = [[Foo alloc] init]; // some non-nil value
if (bar) // true since bar is non-zero
Foo *bar = nil;
if (!bar) // true since !bar mean "not bar" which is "not zero" which is "non-zero"
Foo *bar = [[Foo alloc] init]; // some non-nil value
if (!bar) // false since !bar mean "not bar" which is "not non-zero" which is "zero"

Objective C - differentiate between nil and 'no value'

im building a chart view and I'm giving it a datasource to which it can ask for a Y value that corresponds to a given X index. In some cases, there is no Y value for a given X index. I can't send nil in this circumstance, as 0 may be a perfectly valid Y value. What is the best way in objective C to communicate that there is No Value at all?
It seems to me that you're sending the data between the model and the view using some sort of object, perhaps NSNumber, that's holding a value, and you are retrieving the value by sending it a message, and you know that if the object is nil, the message send will return 0.
That's correct. In this case, simply check if the object is nil, and proceed accordingly:
- (void)plotValue:(NSNumber *)number
{
if (number == nil) {
// no value
} else {
// Value may be 0, but you can now safely plot it.
}
}
Don't use primitives in your data source, instead use NSNumber. Then you can differentiate between nil and an NSNumber storing the value 0.
nil is not 0. They are different.
If you are using NSNumber, then nil is clearly disjoint from the set of NSNumber.
If you are using int, then you can't use nil.
If you don't want to use an object (NSNumber), you can return a negative number (if possible) or the maximum/minimum integer that is unlikely to be returned by the datasource.
I'm assuming you're talking about some scalar like an NSInteger or something. If literally any integer is valid for the Y value, then there is no way to do this. However, most likely there is some practical range, so you can just choose some value outside this range to be "special". For example, Cocoa has the value NSNotFound, which NSArray will return if you ask for the index of an object that is not in the array. It is defined as the largest possible NSInteger. You could reuse this yourself if your Y value will never be NSIntegerMax.
The other option, assuming you don't want to create a special type just for this, would be to have your method return both Y and whether or not Y was actually found. For example, some rough pseudocode:
- (NSInteger)yForX:(NSInteger)x wasFound:(BOOL *)found {
if (yWasFound) {
if (found)
*found = YES;
return y;
} else {
if (found)
*found = NO;
return 0;
}
}
You could use NSNumber, as some have suggested, but I find it a little awkward to deal in NSNumbers just to get nil.

Resources