NSNumber unrecognized selector - ios

The following code
NSMutableString *a = [[NSMutableString alloc] init];
NSMutableString *pivot =[[NSMutableString alloc] init];
int i= 0;
for ( i = 0; i < [columns count]; i++)
{
if ([[[data objectForKey:pivot] class] isKindOfClass:[NSNumber class]])
{
sqlite3_bind_int(sqlStatement, i+1,[[columns objectAtIndex:i] integerValue]);
}
else
{
// NSLog(#"kind of class %# %#",NSStringFromClass([[data objectForKey:pivot] class]) ,[data objectForKey:pivot]);
[pivot setString:[columns objectAtIndex:i]];
[a setString:(NSString*)[data objectForKey:pivot]];
sqlite3_bind_text(sqlStatement, i+1, [a UTF8String], -1, 0);
}
}
a = nil;
pivot = nil;
raises an exception
kind of class __NSCFConstantString
-[__NSCFNumber length]: unrecognized selector sent to instance 0xc94c240
But the log clearly says that [data objectForKey:pivot] is a String! And the test variable is always 0!
I checked in the debug and actually [data objectForKey:pivot] is a Number. And in fact I use an if (not shown) to check if it is a number or not. Obviously, the if fails...

You are casting the class to a string when you try to format it this way, try to get the string name from the class with NSStringFromClass(class) :
id pivotObject = [data objectForKey:pivot];
NSLog(#"kind of class %#", NSStringFromClass([pivotObject class]));
if ([pivotObject isKindOfClass:[NSString class]]) {
[pivot setString:[columns objectAtIndex:i]];
[a setString:pivotObject];
}
Also the isKindOfClass: returns a BOOL not int.
But most importantly:
I think the error in the [pivot setString:[columns objectAtIndex:i]] line, since here you change the pivot variable and then retrieve it from data, But since the pivot variable is changed you request a different key from the data dictionary. This you will get an other value. My code I only grab the pivotData once from data.

Related

Adding a value and key into an NSMutableArray - Objc

I've read and tried a dozen or more variants of my own question, but still need some help please.
I have a large existing array, and I want to add a new object (key and value) to each record.
This is an element in the incoming array:
{
"trip_id": 65,
"arrival_time": "08:56:08",
"departure_time": "08:56:08",
"stop_id": 1161,
"stop_sequence": 8,
"stop_headsign": 0
},
This is what I want to achieve:
{
"trip_id": 65,
"arrival_time": "08:56:08",
"departure_time": "08:56:08",
"stop_id": 1161,
"stop_name": "a stop name",
"stop_sequence": 8,
"stop_headsign": 0
},
This is my code so far -- the commented lines are other attempts:
NSString *nameKey = #"stop_name";
int i=0;
for (i=0; i<stopTimesArray.count; i++) {
NSNumber *stopTimesId = [stopTimesArray[i] valueForKey:#"stop_id"];
int j=0;
for (j=0; j<stopArray.count; j++) {
NSNumber *stopId = [stopArray[j] valueForKey:#"stop_id"];
if (stopId == stopTimesId) {
NSString *stopNameString = [stopArray[j] valueForKey:#"stop_name"];
NSLog(#"stopNameString: %#", stopNameString);
[outgoingStopTimesDictionary setObject:stopNameString forKey:#"stop_name"];
//[outgoingStopTimesArray addObject:outgoingStopTimesDictionary];
//[outgoingStopTimesArray addObjectsFromArray:stopTimesArray[i]];
//[stopTimesArray[i] addObject:#{#"stop_name":stopNameString}];
//[stopTimesArray[i] addObject:#{#"stop_name":stopNameString}];
[stopTimesArray[i] addObject: outgoingStopTimesDictionary];
}
}
}
//NSLog(#"outgoingStopTimesArray: %#", outgoingStopTimesArray);
//NSLog(#"outgoingStopTimesDictionary: %#", outgoingStopTimesDictionary);
//NSLog(#"stopTimesArray: %#", stopTimesArray);
The error I am getting with approach is:
stopNameString: S Monroe Street, NB # 18th Street S, NS
[__NSCFDictionary addObject:]: unrecognized selector sent to instance 0x7fd7f2c22760
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary addObject:]: unrecognized selector sent to instance 0x7fd7f2c22760'
I'm either getting a null dictionary, or an unrecognised object exception when I try to add the dictionary to my array. Please point me to a working answer, and I'll delete my question.
It appears that your goal is to add one new key/value pair to the dictionary at stopTimesArray[i]. Here's your code all cleaned up with what I believe you need:
for (NSMutableDictionary *stopTimesDictionary in stopTimesArray) {
NSNumber *stopTimesId = stopTimesDictionary[#"stop_id"];
for (NSDictionary *stopDictionary in stopArray) {
NSNumber *stopId = stopDictionary[#"stop_id"];
if ([stopTimesId isEqual:stopId]) {
NSString *stopNameString = stopDictionary[#"stop_name"];
stopTimesDictionary[#"stop_name"] = stopNameString;
// Uncomment the following line if "stop_id" is unique within the "stopArray"
// break;
}
}
}
Since it seems your stopTimesArray contains immutable dictionaries, the above code won't work as written. Here is a solution that deals with that:
for (NSInteger i = 0; i < stopTimesArray.count; i++) {
NSDictionary *stopTimeDictionary = stopTimesArray[i];
NSNumber *stopTimesId = stopTimesDictionary[#"stop_id"];
for (NSDictionary *stopDictionary in stopArray) {
NSNumber *stopId = stopDictionary[#"stop_id"];
if ([stopTimesId isEqual:stopId]) {
NSString *stopNameString = stopDictionary[#"stop_name"];
NSMutableDictionary *tempDict = [stopTimesDictionary mutableCopy];
tempDict[#"stop_name"] = stopNameString;
[stopTimesArray replaceObjectAtIndex:i withObject:tempDict];
// Uncomment the following line if "stop_id" is unique within the "stopArray"
// break;
}
}
}
dictTo=[NSDictionary new];
dictTo =
#{
#"vPLocationLat" : [NSString stringWithFormat:#"%#",[[[[json valueForKey:#"result"] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lat"]],
#"vPLocationLong" : [NSString stringWithFormat:#"%#",[[[[json valueForKey:#"result"] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lng"]]
};
arrLocationList =[NSMutableArray new];
arrLocationList =[dictTo[#"data"] mutableCopy];
another Solution
-> Try to implement your Code as per in given Code
NSMutableArray* newArray = [NSMutableArray array];
NSArray* oldArray = outerDictionary[#"scores"];
for (NSDictionary* dictEntry in oldArray) {
NSString* leagueCode = dictEntry[#"league_code"];
if ([leagueCode isEqualToString #"epl"]) {
[newArray addObject:dictEntry];
}
}
Another one Solution
Try something like this.
Assume your array is called array and yourNewNameString is your new value for name
for(NSMutableDictionary *dict in array){
if([[dict objectForKey:#"id"]integerValue]==5){
[dict setObject:yourNewNameString forKey#"name"];
}
}
edit This is assuming you initialized your array with NSMutableDictionarys (Not just NSDictionarys)
//You can create dictionary and add it into NSMutableArray Object Like..
NSMutableArray *arr = [[NSMutableArray alloc] init];
NSDictionary *inventory = #{
#"Mercedes-Benz SLK250" : [NSNumber numberWithInt:13],
#"Mercedes-Benz E350" : [NSNumber numberWithInt:22],
#"BMW M3 Coupe" : [NSNumber numberWithInt:19],
#"BMW X6" : [NSNumber numberWithInt:16],
};
[arr addObject:inventory];
//You can access using key like...
NSString *strForBMWX6 = [[arr objectAtIndex:0] valueForKey:#"BMW X6"];
// in your case you just miss objectAtIndex:j
First, thanks #rmaddy.
I modified his answer a bit, but his was basically correct.
My final code looks like this:
for (NSInteger i = 0; i < stopTimesArray.count; i++) {
NSDictionary *stopTimesDictionary = stopTimesArray[i];
NSNumber *stopTimesId = stopTimesDictionary[#"stop_id"];
for (NSDictionary *stopDictionary in stopArray) {
NSNumber *stopId = stopDictionary[#"stop_id"];
if ([stopTimesId isEqual:stopId]) {
NSString *stopNameString = stopDictionary[#"stop_name"];
NSMutableDictionary *tempDict = [stopTimesDictionary mutableCopy];
tempDict[#"stop_name"] = stopNameString;
[outgoingStopTimesArray addObject:tempDict];
break;
}
}
}

iOS 8 works but iOS 7 crashes with -[NSNull length]: unrecognized selector sent to instance

I've been searching for answers for this but still haven't been able to solve how to correct the problem. This -[NSNull length]: unrecognized selector sent to instance and this [NSNull length]: unrecognized selector sent to instance 0x43fe068 did not help.
I'm working on a chat app with a Parse back-end and I was having a timestamp problem with a chat message showing up out of order so I deleted the rows that were out of order from my Parse database using the Databrowser. When I tested the app, that seemed to fix the problem on my iPhone 6 Plus and on the iPhone 6 simulator both running iOS 8. However, when opening up the same chat room on my iPhone 5s running iOS 7, the app crashes consistently with the following error.
-[NSNull length]: unrecognized selector sent to instance
I have no idea why deleting a row would cause this to happen and why only on iOS 7? I set an All Exceptions Breakpoint and here is the offending line along with a screenshot.
self.lastMessageLabel.textColor = [UIColor redColor];
I still get the NSNull length crash even when I comment out the above line, but it breaks at the generic main.m.
Any suggestions on how to solve this would be appreciated. Thanks.
EDIT 1: Here's the code from my ChatView.m that's being loaded by my PrivateInbox.
- (void)loadMessages {
if (isLoading == NO)
{
isLoading = YES;
JSQMessage *message_last = [messages lastObject];
PFQuery *query = [PFQuery queryWithClassName:PF_CHAT_CLASS_NAME];
[query whereKey:PF_CHAT_ROOM equalTo:chatroomId];
if (message_last != nil) {
[query whereKey:PF_CHAT_SENTDATE greaterThan:[self.dateFormatter stringFromDate:message_last.date]];
}
[query includeKey:PF_CHAT_USER];
[query orderByAscending:PF_CHAT_SENTDATE];
[query addAscendingOrder:PF_CHAT_CREATEDAT];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
{
if (error == nil)
{
for (PFObject *object in objects)
{
PFUser *user = object[PF_CHAT_USER];
[users addObject:user];
if(![object[PF_CHAT_TEXT] isKindOfClass:[NSNull class]]) {
NSDate* sentDate;
if(object[PF_CHAT_SENTDATE] != nil)
sentDate = [self.dateFormatter dateFromString:object[PF_CHAT_SENTDATE]];
else
sentDate = object.createdAt;
JSQTextMessage *message = [[JSQTextMessage alloc] initWithSenderId:user.objectId senderDisplayName:user.objectId date:sentDate text:object[PF_CHAT_TEXT]];
[messages addObject:message];
} else if(object[PF_CHAT_PHOTO] != nil) {
NSDate* sentDate;
if(object[PF_CHAT_SENTDATE] != nil)
sentDate = [self.dateFormatter dateFromString:object[PF_CHAT_SENTDATE]];
else
sentDate = object.createdAt;
PFFile* photoFile = object[PF_CHAT_PHOTO];
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] init];
JSQMediaMessage *photoMessage = [[JSQMediaMessage alloc] initWithSenderId:user.objectId
senderDisplayName:user.objectId
date:sentDate
media:photoItem];
[messages addObject:photoMessage];
{
[photoFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
photoItem.image = [UIImage imageWithData:data];
[self.collectionView reloadItemsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForItem:[messages indexOfObject:photoMessage] inSection:0], nil]];
}];
}
} else if(object[PF_CHAT_VIDEO] != nil) {
NSDate* sentDate;
if(object[PF_CHAT_SENTDATE] != nil)
sentDate = [self.dateFormatter dateFromString:object[PF_CHAT_SENTDATE]];
else
sentDate = object.createdAt;
PFFile* videoFile = object[PF_CHAT_VIDEO];
JSQVideoMediaitem *videoItem = [[JSQVideoMediaitem alloc] initWithFileURL:[NSURL URLWithString:[videoFile url]] isReadyToPlay:YES];
JSQMediaMessage *videoMessage = [[JSQMediaMessage alloc] initWithSenderId:user.objectId
senderDisplayName:user.objectId
date:sentDate
media:videoItem];
[messages addObject:videoMessage];
}
}
if ([objects count] != 0) {
[JSQSystemSoundPlayer jsq_playMessageReceivedSound];
[self resetUnreadCount];
[self finishReceivingMessage];
}
}
else [ProgressHUD showError:#"Network error."];
isLoading = NO;
}];
}
}
EDIT 2: I tried NSNullSafe from Nick Lockwood https://github.com/nicklockwood/NullSafe and that allowed the Private Inbox to open without crashing and gets me past the NSNull Length error but I think that just masks the problem and I still don't know why it didn't crash on iOS 8 but did crash on iOS 7.
I don't think that this could be related to the differences between the 2 operative systems.
The crash is pretty clear, you are sending a message to an object of class NSNUll that can't handle it.
The fact you are using parse or a web services in general makes me think that this object was generated by the back end as a null in a JSON and translated into a NSNull object by the JSON parsing.
You should find a way to handle NSNull object probably at parsing level.
#Andrea is correct, if you can't figure it out from your API (server) side then, here's categories of NSDictionary and NSArray which removes any NSNull object and your app wouldn't crash.
#interface NSDictionary (NullReplacement)
- (NSDictionary *)dictionaryByReplacingNullsWithBlanks;
#end
#interface NSArray (NullReplacement)
- (NSArray *)arrayByReplacingNullsWithBlanks;
#end
#implementation NSDictionary (NullReplacement)
- (NSDictionary *)dictionaryByReplacingNullsWithBlanks {
const NSMutableDictionary *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = #"";
for (NSString *key in self) {
id object = [self objectForKey:key];
if (object == nul) [replaced setObject:blank forKey:key];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced setObject:[object dictionaryByReplacingNullsWithBlanks] forKey:key];
else if ([object isKindOfClass:[NSArray class]]) [replaced setObject:[object arrayByReplacingNullsWithBlanks] forKey:key];
}
return [NSMutableDictionary dictionaryWithDictionary:[replaced copy]];
}
#end
#implementation NSArray (NullReplacement)
- (NSArray *)arrayByReplacingNullsWithBlanks {
NSMutableArray *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = #"";
for (int idx = 0; idx < [replaced count]; idx++) {
id object = [replaced objectAtIndex:idx];
if (object == nul) [replaced replaceObjectAtIndex:idx withObject:blank];
else if ([object isKindOfClass:[NSDictionary class]]) [replaced replaceObjectAtIndex:idx withObject:[object dictionaryByReplacingNullsWithBlanks]];
else if ([object isKindOfClass:[NSArray class]]) [replaced replaceObjectAtIndex:idx withObject:[object arrayByReplacingNullsWithBlanks]];
}
return [replaced copy];
}
#end
Caution : Only appropriate if you're parsing small amount of data.
Source : https://stackoverflow.com/a/16702060/1603234
The other two answers are correct - this is not an issue of OS version, but rather that you are being passed a NULL value and are not catching it.
The line you caught in the Exception:
self.lastMessageLabel.textColor = [UIColor redColor];
Is indicating a symptom, not the cause. I am not 100% sure how _setTextColor actually works, but I would make a strong bet that it works by using the length attribute of NSString/NSAttributedString to make a NSRange so that it knows where to start applying the color and end applying the color. If the data is NULL, then as the other users mentioned, you are trying to access the length attribute of the wrong class, causing your crash.
Judging from your stack trace, lines 5 (setMessage:forUser) and 6 (cellForRow...) are where you should be trying to catch the NULL value. Either that, or you should modify your data controller so that when a NULL value is passed back in the JSON, you replace it with a placeholder, such as "No Message".
At either rate, your crash is probably happening when you assign a value to self.lastMessageLabel.text when you are building your tableView cells in cellForRow.... Check the NSString that you use there for class type (isKindOfClass[NSNULL class]) and see if that helps.

Parsing JSON data and handling an Array

I am using Mantle to parse some JSON data from Yelp.
For each business returned I get an NSArray of categories. This would be an example:
yelpCategories = (
(
"Wine Bars",
"wine_bars"
),
(
"Ice Cream & Frozen Yogurt",
icecream
)
);
yelpCategories is the name of the array that I save. Later on I am trying to parse the array into a string:
NSMutableString *yelpCats = [[NSMutableString alloc] init];
for (NSObject * obj in business.yelpCategories)
{
[yelpCats appendString:[NSString stringWithFormat:#"%#,",[obj description]]];
}
The issue is with the above. I am being returned a string just as "(" so I must be accessing the array incorrectly. How can I correctly access each object, ideally I would be looking for the end string o be #"Wine Bars, Ice Cream & Frozen Yogurt".
EDIT
The categories array: (
(
Pubs,
pubs
)
)
FINAL EDIT - Proposed Solution
for (NSArray *cats in business.yelpCategories)
{
NSString *category = [cats objectAtIndex:0];
if ([category length] > 0) {
category = [category substringToIndex:[category length] - 1];
}
if (cats == business.yelpCategories.lastObject) {
[yelpCats appendString:[NSString stringWithFormat:#"%#",category]];
} else {
[yelpCats appendString:[NSString stringWithFormat:#"%#, ",category]];
}
}
cell.yelpCategories.text = yelpCats;
Using the description of the object gives you what you see in the debugger, which includes extra carriage returns.
What you want to do is something like:
yelpCats = [yelpCategories componentsJoinedByString:#", "];
#jeffamaphone 's answer is the correct and best way of doing things however what your doing will almost work, I think your just confused on the contents of the array.
The yelpCategories array is an array of strings so you don't need to call stringWithFormat or call the description method. In fact [obj description] will return a string so you didn't even need stringWithFormat in your example and you would have gotten the same output. To make your original method work change to:
NSMutableString *yelpCats = [[NSMutableString alloc] init];
for (id obj in business.yelpCategories)
{
//obj is a string so we can just append it.
[yelpCats appendString:obj]];
}
Also noticed I changed NSObject *obj to just id obj, this is the idiomatic way and shorthand way of declaring NSObjects in objective-c. In this example however I would actually use (NSString *category in business.yelpCategories) instead for better readability. In this case you are declaring to everyone that you expect each object in the array to be a string and then if you wanted to use NSString methods on it inside the loop then you don't have to cast it.
for (NSArray *cats in business.yelpCategories)
{
NSString *category = [cats objectAtIndex:0];
if ([category length] > 0) {
category = [category substringToIndex:[category length] - 1];
}
if (cats == business.yelpCategories.lastObject) {
[yelpCats appendString:[NSString stringWithFormat:#"%#",category]];
} else {
[yelpCats appendString:[NSString stringWithFormat:#"%#, ",category]];
}
}
cell.yelpCategories.text = yelpCats;

-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x91da0f0

when i set the value in nsmutabledictionary then given error show in image below....
here my code for setvalue in nsmutabledictionary
NSMutableArray *countArray=[[NSMutableArray alloc] init];
for (int i=0;i<artistName.count;i++)
{
int count=0;
NSMutableDictionary *dir1=[artistName objectAtIndex:i];
NSString *artist1=[dir1 objectForKey:#"SONG_ARTIST"];
for (int j=0;j<CurrentPlayingSong.count;j++)
{
NSDictionary *dir2=[CurrentPlayingSong objectAtIndex:j];
NSString *artist2=[dir2 objectForKey:#"SONG_ARTIST"];
if ([artist2 isEqualToString:artist1])
{
count++;
}
}
NSString *Size=[[NSString alloc] initWithFormat:#"%d",count];
[dir1 setObject:Size forKey:#"SIZE"];
[countArray addObject:dir1];
}
return countArray;
this NSMutableDictionary *dir1=[artistName objectAtIndex:i]; returns a NSDictionary object which turns your dir1 to the same type.
best way is to do something like this:
NSMutableDictionary *dir1=[NSMutableDictionary dictionaryWithDictionary:[artistName objectAtIndex:i]];
or
NSMutableDictionary *dir1 = [artistName[i] mutableCopy];
This will ensure that dir1 will always be NSMutableDictionary.
hope this helps

I've got strange output from 'componentsSeparatedByString' method of NSString

I want to store the array of NSDictionary to a file. So I write a function to convert from NSArray to NSString. But I got a very strange problem. Here is my code.
+ (NSArray *)arrayForString:(NSString*)dataString
{
NSArray* stringArray = [dataString componentsSeparatedByString:ROW_SEPARATOR];
NSLog(#"%#", stringArray);
NSMutableArray* dictionaryArray = [[NSMutableArray alloc] initWithCapacity:0];
for (int i = 0; i < [stringArray count]; i++)
{
NSString* string = [stringArray objectAtIndex:i];
NSLog(#"%#", string);
NSArray* subStrings = [string componentsSeparatedByString:COLUMN_SEPARATOR];
NSDictionary* dic = [[NSDictionary alloc] initWithObjectsAndKeys:[subStrings objectAtIndex:0], PHOTO_NAME, [NSNumber numberWithUnsignedInt:[[subStrings objectAtIndex:1] unsignedIntValue]], PHOTO_SEQ_NO, nil];
[dictionaryArray addObject:dic];
}
return dictionaryArray;
}
Here is the log:
2012-05-05 23:57:35.113 SoundRecognizer[147:707] (
"new Photo/0",
"new Photo/1"
)
2012-05-05 23:57:35.118 SoundRecognizer[147:707] new Photo/0
2012-05-05 23:57:35.123 SoundRecognizer[147:707] -[__NSCFString unsignedIntValue]: unrecognized selector sent to instance 0x1d18c0
How do I get a #"-" from this following array?!
2012-05-05 23:57:35.113 SoundRecognizer[147:707] (
"new Photo/0",
"new Photo/1"
)
NSString doesn't have an unsignedIntValue method. Use intValue instead. But I'm not sure of the point of all this - you can write an array of dictionaries straight to a file anyway (as long as they only contain property list types) using writeToFile: atomically:.

Resources