Invalid Selector on doubleValue - objective-c

A bit new to Objective-C, so please bear with me.
Firstly, I'm using the FMDB library for SQLite management.
I'm populating an NSMutableDictionary using the following method:
//....
while([effectivenessResults next]) //this loops through the results of a query (verified that this works)
{
NSMutableArray *dFactors = [[NSMutableArray alloc]init];
if([resultDict objectForKey:[effectivenessResults stringForColumn:#"tName"]])
{
dFactors = [resultDict objectForKey:[effectivenessResults stringForColumn:#"tName"]];
}
NSNumber *effectivenessValToAdd = [NSNumber numberWithDouble:[effectivenessResults doubleForColumn:#"dFactor"]/100];
[dFactors addObject:[NSMutableString stringWithFormat:#"%#",effectivenessValToAdd]];
[resultDict setObject:dFactors forKey:[effectivenessResults stringForColumn:#"tName"]];
}
I'm returning the array properly (I have verified this). Then, I am accessing this NSMutableDictionary elsewhere, using the follwing method:
for(id type in tEffect) //tEffect is the NSMutableDictionary, returned from the previous code (there known as resultDict)
{
effectivenessString = [self getEffectivenessString:[tEffect objectForKey:type]];
tInfo = [NSMutableString stringWithFormat:#"%#", [tInfo stringByAppendingFormat:#"%#: %#\n", type, effectivenessString]];
}
which calls the following two methods:
-(NSMutableString *)getEffectivenessString:(NSNumber *) numberPassedIn
{
double dFactor = [numberPassedIn doubleValue];
//adds the above value to a string, this will not affect anything
}
and
-(NSNumber *) listProduct: (NSMutableArray *)listOfValues //calculates the product of an NSMutableArray of numbers
{
NSNumber *product=[NSNumber numberWithDouble:1.0];
for(int i = 0; i < [listOfValues count]; i++)
{
NSNumber *newVal = [listOfValues objectAtIndex:i];
product = [NSNumber numberWithDouble:[product doubleValue] * [newVal doubleValue]];
}
return product;
}
So, when I call these methods, I am getting the following error:
2013-08-04 13:52:04.514 effectCalculator[45573:c07] -[__NSArrayM doubleValue]:
unrecognized selector sent to instance 0x8c19e00
2013-08-04 13:52:04.521 effectCalculator[45573:c07] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '-[__NSArrayM doubleValue]: unrecognized
selector sent to instance 0x8c19e00'
Important to note: This error occurs on the retrieval, NOT the populating of the NSMutableDictionary. This means the population of this dictionary not the an issue, but it might have something to do with why it's having trouble retrieving the data.
So what might cause this error?

Your code is pretty difficult to follow. In future please post a minimal sample which compiles, or at least is a single block of understandable code.
Having said that, I believe your issue is with this bit:
for(id type in tEffect) //tEffect is the NSMutableDictionary, returned from the previous code (there known as resultDict)
{
effectivenessString = [self getEffectivenessString:[tEffect objectForKey:type]];
what does resultDict contain?
[resultDict setObject:dFactors ...
but dFactors is an NSMutableArray. Well getEffectivenessString expects a NSNumber, not a NSMutableArray. So it complains. Also I think you intended for the method to take a string, not a number, although I don't see why you're not casting as you load them (instead of as you use them).
Since Objective C doesn't support strongly-typed arrays or dictionaries, your best bet to defend against this in the future is to name your variables more logically. It should stand out when you try to call a method which expects a number with an array instead.

Related

-[NSNull objectForKeyedSubscript:]: unrecognized selector sent to instance

I got an exception that says:
-[NSNull objectForKeyedSubscript:]: unrecognized selector sent to instance
Is it saying I am trying to access an NSNull object with a key?
Any idea what causes this and how to fix it or debug further?
The way to fix it is to not attempt objectForKeyedSubscript on an NSNull object. (I'm betting you're handling some JSON data and aren't prepared for a NULL value.)
(And apparently objectForKeyedSubscript is what the new array[x] notation translates into.)
(Note that you can test for NSNull by simply comparing with == to [NSNull null], since there's one and only one NSNull object in the app.)
What ever value you are storing, despite what the editor tells you, at run time you are storing an NSNull, and later on trying to call objectForKeyedSubscript. I am guessing this happening on what is expected to be an NSDictionary. Some thing like:
NSString *str = dict[#"SomeKey"]
Either a piece of code beforehand is not doing its job and investigate there, or perform some validation:
NSDictionary *dict = ...;
if ( [dict isKindOfClass:[NSDictionary class]] ) {
// handle the dictionary
}
else {
// some kind of error, handle appropriately
}
I often have this kind of scenario when dealing with error messages from networking operations.
I suggest adding a category to NSNull to handle this in the same way you would expect a subscript call to be handled if it it were sent to nil.
#implementation NSNull (Additions)
- (NSObject*)objectForKeyedSubscript:(id<NSCopying>)key {
return nil;
}
- (NSObject*)objectAtIndexedSubscript:(NSUInteger)idx {
return nil;
}
#end
A simple way to test is like this:
id n = [NSNull null];
n[#""];
n[0];
With this category, this test should be handled successfully/softly.

iOS - exception when checking if string is empty

I am doing something like this:
// GET THE USER ID
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *user_id = [standardUserDefaults objectForKey:#"user_id"];
And then checking whether the user_id is empty
if ([user_id length] == 0) {
proceed = false;
NSLog(#"Error: User id is not set.");
}
And I get this runtime exception:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFBoolean length]: unrecognized selector sent to instance 0x1469f70'
Any idea why I get the exception? I didn't think there was anything too wrong with what I was doing.
Thanks!
This:
NSString *user_id = [standardUserDefaults objectForKey:#"user_id"];
Is returning an NSNumber (as NSCFBoolean is a private subclass of NSNumber) rather than a string. It therefore doesn't implement length, causing the exception.
Perhaps you want to test [user_id intValue] > 0? Even if you convert it to a string it'll always have some length.
(side issues raised: merely declaring user_id as a reference to an NSString doesn't mean that anything you assign to it magically becomes a string; indeed there are no type object-type coercion effects whatsoever. The compiler doesn't complain because the NSUserDefaults return objects of type id, i.e. it guarantees they're objects but makes no claims as to their type, and the compiler doesn't know either. All objects may be cast to and from id without generating a warning, so that it can be used by classes such as the user defaults, NSArray, etc, where they can accept anything as long as it's an object).
EDIT: based on issues raised in the comments, it sounds like the thing originally being stored may not be a string. A good way to validate web stuff is probably something like:
// fall through here if the object isn't a string
if(![responseString isKindOfClass:[NSString class]])
{
// check whether it's something that can be converted to a string
if(![responseString respondsToSelector:#selector(stringValue)])
{
// some sort of error condition; the server returned something
// that isn't a string and doesn't convert (in and of itself) to string
}
else
{
// convert the object to a string
responseString = [responseString stringValue];
}
}
The reason you are getting that error is you are trying to call 'length' on what appears to be a boolean. Either way, for checking if a string is blank here are some easy methods you can add to the NSString class by means of a category:
-(BOOL)isBlank{
return [[self trim] length]==0;
}
-(NSString *)trim{
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet] ];
}
Then to call it it's just:
[myString isBlank];

nsdictionary issue

I have the following data in a NSDictionary Variable:
{
value = "TV-PG";
}
I was wondering how to get the value for key "value" here.
I tried:
NSDictionary *fieldMaturityRating = [[parsedItems objectAtIndex:0] objectForKey:#"field_maturity_rating"];
NSString *dateRelease = [fieldMaturityRating objectForKey:#"value"];
(where, fieldMaturityRating is a NSDictionary with the given value)
and I get:
-[__NSArrayM objectForKey:]: unrecognized selector sent to instance 0xd9cd3f0
[10530:707] *** Terminating app due to uncaught exception: -[__NSArrayM objectForKey:]: unrecognized selector sent to instance 0xd9cd3f0
Can anyone kindly help me ?
Thanks.
Note: if I pause the execution and do a po after the 1st line of code presented here, I get the following:
(gdb) po fieldMaturityRatingNew
<__NSArrayM 0x79af250>(
{
value = "TV-PG";
}
)
The po actually shows your issue:
(gdb) po fieldMaturityRatingNew
<__NSArrayM 0x79af250>(
{
value = "TV-PG";
}
)
The outer ( and ) mean that your object is actually an array.
Inside that is where the { and } denote your dictionary.
So you really want:
NSString *value = [[fieldMaturityRatingNew objectAtIndex:0] objectForKey:#"value"];
You're actually sending that NSDictionary message to a NSMutableArray instance.
You might want to check your code again as the objectForKey: method is right when pointing to a NSDictionary.
This means your fieldMaturityRating is not actually an NSDictionary. Make sure you aren't setting it to an array somewhere in your code.
Edit:
This means your fieldMaturityRating is actually an NSArray containing an NSDictionary. If this is your intended data structure then you can access your value like so.
NSString *dateRelease = [[fieldMaturityRating objectAtIndex:0] objectForKey:#"value"];
I don't believe this is your intended data structure so you should look into why your parsedItems array returned you an NSArray instead of an NSDictionary. If you track this problem down you can stop any headaches in the future.
Based on your datastructure which is a dictionary inside an array, dateRelease should be like this
NSString *dateRelease = fieldMaturityRating[0][#"value"];

Fast Enumeration on NSArray of Different Types

I have this question here (as well other quesrtions on SO), and the Apple docs about Objective-C collections and fast enumeration. What is not made clear is if an NSArray populated with different types, and a loop is created like:
for ( NSString *string in myArray )
NSLog( #"%#\n", string );
What exactly happens here? Will the loop skip over anything that is not an NSString? For example, if (for the sake of argument) a UIView is in the array, what would happen when the loop encounters that item?
Why would you want to do that? I think that would cause buggy and unintended behavior. If your array is populated with different elements, use this instead:
for (id object in myArray) {
// Check what kind of class it is
if ([object isKindOfClass:[UIView class]]) {
// Do something
}
else {
// Handle accordingly
}
}
What you are doing in your example is effectively the same as,
for (id object in myArray) {
NSString *string = (NSString *)object;
NSLog(#"%#\n", string);
}
Just because you cast object as (NSString *) doesn't mean string will actually be pointing to an NSString object. Calling NSLog() in this way will call the - (NSString *)description method according to the NSObject protocol, which the class being referenced inside the array may or may not conform to. If it conforms, it will print that. Otherwise, it will crash.
You have to understand that a pointer in obj-c has no type information. Even if you write NSString*, it's only a compilation check. During runtime, everything is just an id.
Obj-c runtime never checks whether objects are of the given class. You can put NSNumbers into NSString pointers without problems. An error appears only when you try to call a method (send a message) which is not defined on the object.
How does fast enumeration work? It's exactly the same as:
for (NSUInteger i = 0; i < myArray.count; i++) {
NSString* string = [myArray objectAtIndex:i];
[...]
}
It's just faster because it operates on lower level.
I just tried a quick example... Here is my code.
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1];
NSNumber *number = [NSNumber numberWithInteger:6];
[array addObject:number];
[array addObject:#"Second"];
Now if I simply log the object, no problem. The NSNumber instance is being cast as an NSString, but both methods respond to -description, so its not a problem.
for (NSString *string in array)
{
NSLog(#"%#", string);
}
However, if I attempt to log -length on NSString...
for (NSString *string in array)
{
NSLog(#"%i", string.length);
}
... it throws an NSInvalidArgumentException because NSNumber doesn't respond to the -length selector. Long story short, Objective-C gives you a lot of rope. Don't hang yourself with it.
Interesting question. The most generic syntax for fast enumeration is
for ( NSObject *obj in myArray )
NSLog( #"%#\n", obj );
I believe that by doing
for ( NSString *string in myArray )
NSLog( #"%#\n", string );
instead, you are simply casting each object as an NSString. That is, I believe the above is equivalent to
for ( NSObject *obj in myArray ) {
NSString *string = obj;
NSLog( #"%#\n", string );
}
I could not find precise mention of this in Apple's documentation for Fast Enumeration, but you can check it on an example and see what happens.
Since all NSObject's respond to isKindOfClass, you could still keep the casting to a minimum:
for(NSString *string in myArray) {
if (![string isKindOfClass:[NSString class]])
continue;
// proceed, knowing you have a valid NSString *
// ...
}

Terminating the app due to uncaught exception in Objective-C for iPhone app

i've written a for loop in Objective-C, This is how my code looks like
NSString *string = [NSString stringWithContentsOfFile=#"/Users/Home/myFile.doc"];
NSString *seperator=#"\n";
NSArray *mainarray = [string componentsSeparatedByString:seperator];
// Since i want to parse each element of mainarray
for(NSString *s in mainarray)
{
//again parising the string using a new separator
NSString newseparator = #"=";
NSArray *subarray = [s componentsSeparatedByString : newseparator];
//Copying the elements of array into key and object string variables
NSString *key = [subarray objectAtIndex:0];
NSLog(#"%#",key);
NSString *class_name= [subarray objectAtIndex:1];
NSLog(#"%#",class_name);
// create an instance for the class_name
//dont knw how it ll take the value from file and ???
//Putting the key and objects values into hashtable
NSMutableDictionary = [NSDictionary dictinaryWithObject:class_name forKey:key];
}
Whenever i execute this code this crashes my program saying as, Terminating the app due to uncaught exception NSRangeException
How to know the range of array and how to specify the terminating condition in the for loop???and plz let me knw how to handle this exception???
I'm surprised that code even compiles. If I remember correctly, it can't compile unless you have gone to great lengths to turn off a whole bunch of compiler warnings.
NSString newseparator = #";";
That should give an error write there in that you don't have the *.
NSString *key = [subarray objectAtIndex[0]];
NSString *object = [subarray objectAtIndex[1]];
Neither of these lines of code make any sense.
It would appear that you haven't posted the actual code?
Now, getting back to the exception. A range exception will be tossed if you try to access an item at an index that is outside of the range of indexes available in the array. Thus, if componentsSeparatedByString: returned an array of 0 or 1 elements, then [subarray objectAtIndex: 1]; will cause a range exception to be raised.
What you don't want to do is to try and handle the exception using an #catch block. In Cocoa (and iPhone development), exceptions are treated as non-recoverable errors.
So, instead, use the -count method on NSArray to verify that the array actually contains the # of elements you were expecting. Since you are writing a casual parser, this is probably a good idea as a minimal check of input validity.