for(NSString *key in [rewards allKeys]) crashes the application? - iphone

I have an application which is having a dictionary returned from a webservice.and i am passing that dictionary to another view controller.
and in this
NSDictionary *rewards=[rewardsdictionary objectForKey:#"rewards"];
NSLog(#"%#",rewards);
NSMutableArray *dataArray=[[NSMutableArray alloc] init];
for(NSString *key in [rewards allKeys])
{
NSDictionary *dict1=[rewards objectForKey:key];
[dataArray addObject:dict1];
}
self.rewardsarray=[[NSMutableArray alloc] init];
self.rewardsarray=dataArray;
But in this line for(NSString *key in [rewards allKeys]) the application is crashing.but when i am printing rewards or rewards dictionary the values are there.
-[__NSArrayM allKeys]: unrecognized selector sent to instance 0x76636b0
can anybody help me to get out of this?

Obviously, rewards is not a NSDictionary. It's an NSArray.

Use NSAssert to check if rewards is an NSDictionary before sending allKeys message to it.

Related

JSONKit invalid arguement when try to copy

I am parsing JSON data with JSONKit as NSMutableDictionary.
NSString *str = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
NSMutableDictionary *jsonResponse = [self.responseData objectFromJSONData];
NSMutableDictionary *newData = [[NSMutableDictionary alloc] init];
[newData addEntriesFromDictionary:[jsonResponse mutableCopy]];
When i do this i am getting this error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSMutableDictionary addEntriesFromDictionary:]: dictionary argument is not an NSDictionary'
I am trying to figure out what is causing this problem. I know that jsonResponse is an object of JKArray from my other experience.
I need help.
Thanks.
Try the following:
id object = [self.responseData objectFromJSONData];
NSLog(#"%#", [object class]);
Most likely your response is an array instead of a dictionary.
If you really want to convert the array into a dictionary, you could do something like this, using a self-defined key:
NSArray *array = [self.responseData objectFromJSONData];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:array forKey:#"posts"];
Though perhaps there are some better options if you could show me the contents of your array.

How to set array value and key in NSDictionary in iphone?

Here i am using NSMutableArray to store date, then i tried to set key and assign ArrayValue in dictionary but the app crashed, please help me
Thanks in ADvance
Here i tried the code for your reference:
[DateArray addObject:dateString]; //NSMutablArray
NSMutableDictionary *myDictionary =[[NSMutableDictionary alloc]init];
[myDictionary setObject:DateArray forKey:#"Date"]; //put array value and set key in NSDictionary.
NSDictionary Class is immutable. You must convert to NSMutableDictionary.
If you are using XCode version 4.4 or later you can jus do this:
[dateArray addObject:dateString]; //NSMutablArray
NSDictionary *myDictionary = #{ #"Date", dateArray };
You are using NSDictionary. You should use NSMutableDictionary.
NSDictionary is immutable. If you want to use NSDictionary then use below method:
- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
You're using an NSDictionary when you should be using NSMutableDictionary
Try this line :
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];
Most of the collection classes in iOS have a mutable and nonmutable version (i.e.
NSArray -> NSMutableArray
NSSet -> NSMutableSet
NSDictionary -> NSMutableDictionary
(and others)
A mutable version will let you modify the contents. However, if you know you're not going to change it then a non mutable version will be slightly faster to use.
You can (usually) get a mutable class from a nonmutable one by using the mutableCopy method i.e.
// This array can't be changed
NSArray *myArray = #[ #"A", #"B", #"C" ];
// This array contains everything from the previous array but can now be modified
MSMutableArray myArray2 = [myArray mutableCopy];
NB : There are also other classes that have mutable subclasses i.e. NSURL -> NSMutableURL
Do it like this:
for(int i=0;i<[DateArray count]; i++)
{
[myDictionary addObject:[DateArray objectAtIndex:i] forKey:#"Date"];
}

How to dissect and reorganize info in an NSDictionary

So I have an array of NSDictionaries, each NSDictionary has a bunch of key/value pairs pertaining to aspects of a photo (from Flickr).
I'm making an app that has a UITableViewController whose cells should be each of the different categories of the photos. So in pseudocode, I'm trying to construct a new NSDictionary (with keys being categories of photos, values being the NSDictionaries of the photos that contains that key). I'm iterating through each NSDictionary in the initial array, getting the category tags, and saying, if my new NSDict doesn't contain this key, make a new key to an empty array. Then add the current NSDict to that array. I'm getting consistent errors, not sure why.
Here's the diluted code.
photoList = [FlickrFetcher photosWithTags:[NSArray arrayWithObjects: #"CS193p_SPoT", nil]];
NSLog(#"%#", photoList);
categories = [[NSDictionary alloc] init];
NSArray *temp = [[NSArray alloc] init];
for (id obj in photoList) {
temp = [[obj objectForKey:#"tags"] componentsSeparatedByString:#" "];
for (id string in temp) {
if (![categories objectForKey:string]) {
NSMutableArray *arr = [[NSMutableArray alloc] init];
[categories setObject:arr forKey:string];
//[arr release];
}
NSMutableArray *photos = [categories objectForKey:string];
[photos addObject:obj];
[categories setObject:photos forKey:string];
}
}
Thanks!
NSDictionary doesn't have a method setObject:forKey:. You need an NSMutableDictionary.
self.categories = [NSMutableDictionary dictionary];
Other than that, please do use Joost's excellent rewrite of your code.
SIGABRT, just so you know, most likely means that an assertion somewhere failed. In this case, it may be an assertion all the way down in CoreFoundation*; CF checks for mutability when you try to access a dictionary like that and causes an interrupt if the object isn't mutable.
*I have just learned about the CF source's availability recently and have been looking through it, so this may be just "new thing" bias and incorrect.
I don't notice any errors (syntax-errors, that is) in your code, however here is an updated piece of code which has been implemented a bit cleaner (and without memory leaks)
self.photoList = [FlickrFetcher photosWithTags:[NSArray arrayWithObjects: #"CS193p_SPoT", nil]];
NSLog(#"%#", photoList);
self.categories = [NSDictionary dictionary];
for (NSDictionary *obj in photoList) {
NSArray *temp = [[obj objectForKey:#"tags"] componentsSeparatedByString:#" "];
for (NSString *string in temp) {
NSMutableArray *photos = [categories objectForKey:string];
if (!photos) {
photos = [NSMutableArray array];
[categories setObject:photos forKey:string];
}
[photos addObject:obj];
}
}
If it's not working please tell us the exact warning, and were it is caused.

Replace a value in NSDictionary in iPhone

I have a array (dataArray) of NSDictionary "item". It has datas like "david" for key "name" and "85" for key "marks" etc for 5 students. I want to replace the mark of david to 90 with respect to the array index value (ie 0 for dictionary containing david and 85). How can I do it?
The code for content in array is
[item setobject:name forkey:#"Name"];
[item setobject:mark forkey:#"Marks"];
[dataArray addOject:item]
The above code goes inside parsing, so i have array with 5 objects (students), their name and marks, now I want to replace the mark of the first object in the dataArray.
Here's what you can do:
NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init];
NSDictionary *oldDict = (NSDictionary *)[dataArray objectAtIndex:0];
[newDict addEntriesFromDictionary:oldDict];
[newDict setObject:#"Don" forKey:#"Name"];
[dataArray replaceObjectAtIndex:0 withObject:newDict];
[newDict release];
Hope this helps!
You first need an NSMutableDictionary with it you can change the key and value.
It would be like this:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"david", #"name", "85", #"marks", nil];
[dict setObject:#"90" forKey:#"david"];
// NSDictionary *dict = ...
NSMutableDictionary *mutableDict = [dict mutableCopy];
[mutableDict setObject:#"myObject" forKey:#"myKey"];
dict = [mutableDict mutableCopy];
I hope it helps
If you want to update an object in a NSDictionary you should use NSMutableDictionary instead.
NSMutableDictionary has the following EXTRA methods
Adding Entries
setObject:forKey:
setValue:forKey:
addEntriesFromDictionary:
setDictionary:
Removing Entries
removeObjectForKey:
removeAllObjects
removeObjectsForKeys:
[davidsRecord setObject:#"100" forkey:#"mark"];

Releasing NSArray containing NSDictionary objects

I am having difficulty getting my head around memory management in the following segment of code on iPhone SDK 3.1.
// Create array to hold each PersonClass object created below
NSMutableArray *arrayToReturn = [[[NSMutableArray alloc] init] autorelease];
NSArray *arrayOfDictionaries = [self generateDictionaryOfPeople];
[arrayOfDictionaries retain];
for (NSDictionary *dictionary in arrayOfDictionaries) {
PersonClass *aPerson = [[PersonClass alloc] init];
for (NSString *key in [dictionary keyEnumerator]) {
if ([key isEqualToString:[[NSString alloc] initWithString: #"FIRST_NAME"]])
aPerson.firstName = [dictionary objectForKey:key];
else if ([key isEqualToString:[[NSString alloc] initWithString: #"LAST_NAME"]])
aPerson.lastName = [dictionary objectForKey:key];
}
// Add the PersonClass object to the arrayToReturn array
[arrayToReturn addObject: aPerson];
// Release the PersonClass object
[aPerson release];
}
return arrayToReturn;
The [self generateDictionaryOfPeople] method returns an array of NSDictionary objects. Each NSDictionary object has two keys "FIRST_NAME" and "LAST_NAME" with a person's first name and last name as the respective data. The code is looping through each dictionary object in the arrayOfDictionaries array and assigning the dictionary data to the relevant property of an aPerson (PersonClass) object. This object is then added to an array which is returned from this method.
When running instruments I am getting a leak for the dictionary objects contained in the arrayOfDictionaries array. The code within the [self generateDictionaryOfPeople] method is calling [dictionaryObject release] on each NSDictionary object as it is created and added to the array, which makes the retain count on the object 1 (as adding the object to the array would make the retain count 2, but then my release message decrements it back to 1).
I assume this leak is because I am never releasing the arrayOfDictionaries array, and thus the NSDictionary objects within the array are never released. If I attempt to release the array at the end of the above segment of code I get a "message sent to deallocated instance" error. I understand why this is occurring, because I am assigning the aPerson object data within a dictionary item (that I am subsequently releasing) but I don't know where else I can release the arrayOfDictionaries array. Any help would be greatly appreciated.
Thanks!
EDIT: Below is the implementation for [self generateDictionaryOfPeople]
- (NSArray *)generateDictionaryOfPeople {
NSMutableArray *arrayFromDatabase = [[[NSMutableArray alloc] init] autorelease];
// ** Query the database for data **
while ( there are rows being returned from the database ) {
// Declare an NSMutableDictionary object
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
// Loop through each column for that row
for ( while there are columns for this row ) {
columnTitle = title_of_column_from_database
columnData = data_in_that_column_from_database
// Add to the dictionary object
[dictionary setObject:columnData forKey:columnTitle];
// Release objects
[columnName release];
[columnTitle release];
}
// Add the NSMutableDictionary object to the array
[arrayFromDatabase addObject:dictionary];
// Release objects
[dictionary release];
}
// Return the array
return arrayFromDatabase;
}
Here,
if ([key isEqualToString:[[NSString alloc] initWithString: #"FIRST_NAME"]])
aPerson.firstName = [dictionary objectForKey:key];
else if ([key isEqualToString:[[NSString alloc] initWithString: #"LAST_NAME"]])
aPerson.lastName = [dictionary objectForKey:key];
Replace them with
if ([key isEqualToString:#"FIRST_NAME"])
aPerson.firstName = [dictionary objectForKey:key];
else if ([key isEqualToString:#"LAST_NAME"])
aPerson.lastName = [dictionary objectForKey:key];
The problem of the leak is you're creating 1 ~ 2 NSString-s per loop without -release-ing them. If you need constant NSString-s, just directly use them.
I am still getting the original leak due to not releasing the arrayOfDictionaries array.
That means you forgot to autorelease it in generateDictionaryOfPeople.
You need to review the memory management rules.
You are not releasing arrayFromDatabase. (The simplest way to avoid this kind of mistake is to use factories and autorelease as early as possible rather than defer releases manually. In this case, use [NSMutableDictionary dictionary] instead of [[NSMutableDictionary alloc] init].)