Compare NSNumber with NSInteger - iphone

I spent some time today chasing down two bugs, and ended up fixing both of them using the same solution.
Now that I have the solution, I was hoping to get some clarity behind it.
I'm comparing an attribute from Core Data (Integer 16/NSNumber) with an Integer (ABPropertyID & ABMultiValueIdentifier).
The bug was in this comparison, and oddly enough, only showed itself after I had killed the app (from the background tray), reopened it, and run through the same process that included the comparison. Anyways...
This is what stopped working after a restart:
if (myNumber.aProperty == [NSNUmber numberWithInt:anInteger]) { /* do stuff here */ }
And these are the two solutions, which so far, are working perfectly:
if ([myNumber.aProperty integerValue] == anInteger) {/* do stuff here */ }
if ([myNumber.aProperty isEqualToNumber:[NSNumber numberWithInt:anInteger]]) { /* do stuff here */ }
To me, they all look identical. I'm always either converting the NSNumber to an integerValue, or converting the integer to an NSNumber.
Any ideas?

Do not use == to compare NSNumbers. Most of the time you'll be comparing two distinct objects, so the comparison won't evaluate to true. If you look at your if condition, notice that you're particularly comparing your property to a brand new NSNumber object.
Since NSInteger is a Cocoa wrapper for certain value types, comparing NSIntegers with == works fine.
The implementation of isEqualToNumber: probably takes the wrapped value types and compares them too.

As you said, both solutions are working...
I would prefer the first one, as it appears more readable, IMHO...
It may also be more performant, as you are comparing integers, after having converted a NSNumber to an int.
In the second one, you convert an int to an object, then you compare the two objects...
So that's a second method call, which you don't have in the first case...
Hope this helps... : )

netWorkingButtonsIndexes is the array which holds objects and
LinkedIn is a number with int data type.
[[netWorkingButtonsIndexes objectAtIndex:buttonIndex] isEqual:[NSNumber numberWithInteger:LinkedIn]]
By using the isEqual method we can compare objects with any data rtype.

Related

iOS Obj-C: Variable object that can be assigned as a double or a string?

I'm pretty new to iOS development, and I want to figure out if there's a good way to handle this issue. Basically, I'm making a technical calculator that returns some product specifications based on user input parameters. The product in question has specs for some, but not all user parameters, so I . In a constants file, I have a bunch of ATTEN_SPEC_X variables which are const double or const NSString *. Now, it's perfectly okay to be missing a spec, so my plan was to leverage NSArray's ability to hold different types and use introspection later to handle strings vs doubles before I report the returned specs.
Here's an incomplete example of one method I'm implementing. It's just a big conditional tree that should return a two-element array of the final values of spec and nominal.
- (NSArray *)attenuatorSwitching:(double *)attenuator{
double spec, nominal;
{...}
else if (*attenuator==0){
spec=ATTEN_SPEC_3; //this atten spec is a string!
nominal=ATTEN_NOM_3;
}
{...}
return {array of spec, nominal} //not actual obj-c code
So instead of making spec and nominal doubles, can I make them some other general type? The really important thing here is that I don't want to use any special handling within this method; another coder should be able to go back to the constants file, change ATTEN_NOM_3 to a double, and not have to retool this method at all.
Thanks.
The problem you'll run into is that NSArrays can't directly handle doubles. However, you can get around this if you start using NSNumber instances instead - you can return an NSArray * containing an NSString * and an NSNumber * with no problems. If you need even more general typing, the Objective-C type id can be used for any object instance (though still not with primitives; you can't make a double an id).
Later, when you get an array, you can use the NSObject method -isKindOfClass: to determine the type of object you're pulling out of the array, and deal with the string or number depending on the resultant type. If you need to convert your NSNumber back to a double, just use the NSNumber instance method -doubleValue to unbox your double. (+[NSNumber numberWithDouble:] goes the other way, giving you an NSNumber out of a double.)
If you're using a recent enough version of Xcode, you can even make these things literals, rather than having to litter calls to +numberWithDouble: all over the place:
return #[ #3, #"number of things" ]

String compare vs Class compare in objective-C

I'm writing an objective-C game and I'm at the stage where i should start optimising some of my code in the game loops.
I have an extensive amount of class compare methods used,
if ([obj isMemberOfClass:[SomeClass class]])
etc.
I heard this sort of checking is quite expensive, because I choose only to have 1 array populated with multiple classes, I need some sort of class check.
I was thinking perhaps that adding a property to NSObject subclassing NSObject to contain a string property, that during initialisation i would make equal to the class name of that particular subclass. Then simply doing a
if ([obj.klass isEqualTo:#"SomeClass"])
Would this be beneficial?
I'm trying to keep as much dynamic coding out of the game loops as possible.
Thanks!
Short answer: no. String comparison is prohibitively more expensive compared to other methods of comparing (or: classifying, categorizing) objects.
Long answer: don't optimize what you haven't analyzed, measured and compared. What you really want to do before you start optimizing is to get a clear picture of how your app behaves and what its performance bottlenecks are. The change you're attempting is unlikely to lead to any noticeable change in performance, so I suggest to first find the real bottlenecks.
In this particular case, sending isEqual to an NSString is 4 times slower than isMemberOfClass if the test fails. And such conditional tests fail most of the time, which is why you should ignore the results of the test succeeding.
The successful string comparison is fast because it's a simple pointer comparison, if two strings are equal it is likely that they point to the same memory address. If they're not equal, then each character in the string will be compared for equality, probably by using the hash method.
Here are the results of the Object Comparison tests that I added to my performance test project. You can use that project to make further tests.
This is not really a direct answer to your question but is an answer in a broader sense.
In Objective-C the philosophy is more like that of Smalltalk in which you send the message and let the object decide what to do with it. If you find yourself having to do lots of tests to see what class an object is, you need to rethink your design.
For instance, if you have an array of objects and you want to convert each one to an integer to do some maths on it, you can do something like this:
for (id anObj in array)
{
int anInt = [anObj intValue];
// do something with anInt
}
It doesn't matter what the class of each anObj is, you can send -intValue to it. If your array is full of NSStrings and NSNumbers, for example, it doesn't matter, the code above will do what you expect.
Many classes do not define a method for the selector -intValue. For example, if you send that message to an instance of NSData it will respond by throwing an exception. There are a couple of ways to resolve this depending on circumstances.
ignore objects that don't respond to the selector by testing to see if the object knows about the selector
for (id anObj in array)
{
if ([anObject respondsToSelector: #selector(intValue)])
{
int anInt = [anObj intValue];
// do something with anInt
}
}
Define the selector for all classes you know will be put in the array. This is done by declaring a category. This way you can extend any Objective-C class without subclassing. For instance, you can define an intValue method for NSData that returns its length, or the sum of its bytes or some other appropriate value.
Formalise the requirement by declaring a protocol. You can then test for conformance to the protocol, or rely on compile time checks to make sure the objects you put in the array conform to the protocol.
There are lots of things you can do, but you need to get away a bit from the C++/Java model of class hierarchies. Objective-C is much more flexible in that respect.

Checking if NSMutableArray contains values from another array

I have an 3 NSMutableArray objects that contain CMTime objects. How can I iterate through all three of them in an efficient manner and find out if there are duplicate values in all three? For example, I'm iterating through one of time and reading the value and storing it in x. Now, I want to see if x occurs (at any position) within the other two arrays. I tried looking for a contains method, but couldn't find one. I did come across filterUsingPredicate, but I'm not sure if this is the best way of doing it nor how to actually use predicates.
I tried looking for a contains method, but couldn't find one.
Use indexOfObject:
like this:
if ([array indexOfObject:object] != NSNotFound) {
// object found
}
else {
// object not found
}
You can use ([yourArray indexOfObject:x] != NSNotFound) in place of your missing contains method. However, if you're doing this quickly, often, or with a lot of elements, you should consider using NSMutableOrderedSet, which is ordered like NSMutableArray, but offers a quick and efficient contains method, as well as allowing quick operations like union and intersection, which might allow you to redesign your algorithm to iterate through your elements much less.

String comparison failing to function properly in Objective-C

I'm all quite new to Objective-C and pointers and whatnot, so go easy on me.
Basically, i have a place in my code where i extract NSDictionaries from an NSArray based on their date key.
I check for equality by doing this:
if ([[dictItem valueForKey:#"Date"] isEqualToString: date])
Strangely though, it only becomes true for one of the many objects, namely the one with the same pointer value.
How can i explicitly and beyond any doubt compare the VALUE of two strings and NOT the pointer address?
Thanks.
Edit: Perhaps i should mention that for all the comparisons on which it fails, the date has been inserted into the dictionary from a textFields text-property, if that matters.
Your code should work. Are you sure [dictItem valueForKey:#"Date"] is not nil?
Have you tried comparing without the dictionary, that is, storing one of the strings in some variable directly, just to check if that works?
Also, you might want to consider using actual NSDate objects. You can convert String to NSDate and vice versa with NSDateFormatter.

Most efficient way to find out if an object is already in an NSMutableArray?

I just want to know if an object is in an array or not.
So I can use:
- (BOOL)containsObject:(id)anObj
But it would send -isEqual to every object in the array. Bad when there are thousands of them.
And then there is:
- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject
which seems to only compare the memory addresses. I think this is faster. But a bit nasty to use, of course. One would have to check for NSNotFound.
Is -indexOfObjectIdenticalTo really the best option?
if you really need this often, you can create an instance method by category:
#interface NSArray (MONStuff)
- (BOOL)mon_containsObject:(id)object;
#end
#implementation NSArray (MONStuff)
- (BOOL)mon_containsObject:(id)object {
return NSNotFound != [self indexOfObjectIdenticalTo:arg];
}
#end
or these's also CFArrayContainsValue.
a simple function would also suffice.
But a bit nasty to use
Why? It seems to me that
if ([array indexOfObjectIdenticalTo: foo] != NSNotFound)
{
// do what you need
}
is not much more nasty than
if ([array containsObject: foo])
{
// do what you need
}
Which one you choose depends on what equality semantics you use. You almost certainly want to use -containsObject: for arrays containing NSStrings or NSNumbers because -isEqual: gives the correct equality semantics.
Both methods, by the way are O(n) which is where the real performance problem is. If the idea of a linear search is a problem, consider a different data structure e.g. based on NSDictionary.
As per your explaining and comparison indexOfObjectIdenticalTo seems me the first choice to use..
Here is one more SO post ..
indexOfObject vs. indexOfObjectIdenticalTo
If possible (for example if sorting order is irrelevant) you could use an NSDictionary instead, with your object as keys and values of [NSNull null]. Note that the objects get copied when used as keys ! Your objects would need to implement the - (NSUInteger)hash method.
Also see the excellent NSArray or NSSet, NSDictionary or NSMapTable analysis from Matt Gallagher.