I am not quite sure I understand how to do the following.
If I wanted to add e.g. an author and a title (key, value) to a dictionary. Fill that dictionary with data, then have another dictionary for say e.g. k = genre v = artist name and fill it with data.
Then I want to add the dictionaries to an array.
Firstly how is that done? and secondly, what if I allow the user to log their own entries. So I have to textfields on screen, when the user is done, it stores the fields as key value pair in a new dictionary e.g. user's dictionary.
What will I do later when trying to fill a tableview with the users entered data, I dont know the keys or values in that dictionary so how could I retrieve that data?
I mean let's say I want to load the user's dictionary from array index 2 and fill a tableview's cells with each dictionary entry, how is this done? Maybe a method like on an array(get entry.title at index blah blah ), get Key value in dictionary?
How else can one actually get loaded user entered data that they arent aware of the values?
Regards
Add author and title to a dictionary (assuming they're objects that already exist - likely NSString instances in your case):
NSMutableDictionary *books = [[NSMutableDictionary alloc] initWithCapacity:10];
[books setObject:title forKey:author];
Same thing for genre/artist:
NSMutableDictionary *music = [[NSMutableDictionary alloc] initWithCapacity:10];
[books setObject:artist forKey:genre];
Then put them in an array:
NSArray *theArray = [NSArray arrayWithObjects:books, music, nil];
Then to read out the stuff at array index 2:
id key;
NSDictionary *theDictionary = [theArray objectAtIndex:2];
id value;
for (key in [theDictionary allKeys])
{
value = [theDictionary objectForKey:key];
// do something with the value
}
You can get an NSArray of keys in the dictionary using allKeys. Then you can retrieve the values using objectForKey:
for (id key in [myDict allKeys]) {
NSLog(#"key: %#, value: %#", key, [dictionary objectForKey:key]);
}
Related
I am setting up a NSDictionary object so that NSDictionary *scoreObject has the name of the player for its key, and then a mutable dictionary of { date : score } for its values. To get the data, I am pulling a custom class I made in Parse, which have the attributes "Name", "Score" and "createdAt".
I am trying to set up the structure so that the above could be automatically pulled across each row of data in Parse, but am running into trouble when I have two rows of data for the same Name, which gets set as keys in my scoreObject. For example, if Bob has two scores and two createdAt dates, how would I be ale to simply expand the values dictionary so that both could still be stored under the key = "Bob"?
Thanks!
Try something like this:
NSDictionary *dict;
//this is the dictionary you start with. You may need to make it an NSMutableDictionary instead.
//check if the dictionary contains the key you are going to modify. In this example, #"Bob"
if ([[dict allKeys] containsObject:#"Bob"]) {
//there already is an entry for bob so we modify its entry
NSMutableDictionary *entryDict = [[NSMutableDictionary alloc] initWithDictionary:dict{#"Bob"}];
[entryDict setValue:#(score) forKey:#"Date"];
[dict setValue:entryDict forKey:#"Bob"];
}
else {
//There is no entry for bob so we make a new one
NSDictionary *entryDict = #{#"Date": #(score)};
[dict setValue:entryDict forKey:#"Bob"];
}
Here's some code to help you. You may have to adapt something to your case:
Allocating your main dict somewhere:
// assuming its a property
self.scoreObject = [NSMutableDictionary new];
Now, whenever you will set a new pair date/score for a name, first check if that name already has any entry. If yes, use the previous allocated NSMutableDictionary to store the new pair. If not, allocate one and then set the new pair.
I'm encapsulating it in a method that receives the date and the score.
-(void)addNewScore:(NSString*)score AndDate:(NSString*)date forUsername:(NSString*)username
{
NSMutableDictionary *scoresForUser = self.scoreObject[username]; //username is a string with the name of the user, e. g. #"Bob"
if (!scoresForUser)
{
scoresForUser = [NSMutableDictionary new];
self.scoreObject[username] = scoresForUser
}
scoresForUser[date] = score; //setting the new pair date/score in the NSMutableDictionary of scores of that giver user.
}
ps: I used date and score as string in the example, but you can user NSDate or NSNumber with no change if you want.
Now, you are able to list all scores of a user with something like this:
-(void)listScoresForUser:(NSString*)username
{
NSMutableDictionary *scoresForUser = self.scoreObject[username];
for (NSString *date in [scoresForUser allKeys]) {
NSString *score = scoresForUser[date];
NSLog(#"%# - score: %#, createdAt: %#", username, score, date);
}
}
In this way, you should be able to store the data in the structure you want. Please let me know if that is something like you were looking for.
I have an NSMutableArray of elements and I want to be able to conditionally set custom flags for some of the elements. For example an error count for certain elements if they return an error. If the count is more than 3, I would like to delete this element from an array.
What would be the best way to implement such behaviour?
A few options:
Have a separate array holding your counter for each object. When deleting one from your original array, remember to delete it's corresponding counter object.
Create a small class that contains an int value and whatever other object you are storing in the array, and populate your NSMutableArray with that object. You will then have your object and the error counter on the same place
Edit: The second option is the most scalable one, if you ever want to add more flags or whatever to it.
You would be better off creating a mutable array filled with mutable dictionaries. This would allow you have two keys corresponding to each index in the array:
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"some text, or what ever you want to store",#"body",
[NSNumber numberWithUnsignedInteger:0],#"errorCount",
nil];
[myMutableArray addObject:mutableDictionary];
And then here is a basic example of how to increment the error count for a specific item in the array:
- (void)errorInArray:(NSUInteger)idx
{
if ([[[myMutableArray objectAtIndex:idx] objectForKey:#"errorCount"] unsignedIntegerValue] == 2) {
[myMutableArray removeObjectAtIndex:idx];
}else{
NSUInteger temp = [[[myMutableArray objectAtIndex:idx] objectForKey:#"errorCount"] unsignedIntegerValue];
temp ++;
[[myMutableArray objectAtIndex:idx] setObject:[NSNumber numberWithUnsignedInteger:temp] forKey:#"errorCount"];
}
}
As alluded above, no need for custom object creation necessarily:
Creating a mutable array, creating a dictionary with objects/keys and adding said dictionary to the array:
NSMutableArray *myArray = [[NSMutableArray alloc] init] autorelease];
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"John Doe", #"elementName",
[NSNumber numberWithInt:0], #"errorCount",
nil];
[myArray addObject:myDictionary];
I am trying to retrieve the value for a key in a NSDictionary. The dictionary has been initialised with key value pairs both of type string. The trouble is, I cannot seem to retrieve the value with I call objectForKey or valueForKey.
I am able to iterate over the dictionary and print both keys and values.
Can someone point out where im going wrong? Here is my code...
//Set up dictionary with options
keys = [NSArray arrayWithObjects:#"red", #"blue", nil];
values = [NSArray arrayWithObjects:#"1.7", #"2.8", nil];
conversionOptions = [NSDictionary dictionaryWithObject:values
forKey:keys];
Then this is called on the select row in a picker
NSLog(#"... %#", [keys objectAtIndex:row]); //prints out the key
NSString *theString = [keys objectAtIndex:row]; //save it as a string
NSLog(#"The string is... %#", theString); //print it out to make sure im not going crazy
NSLog(#"the value is : %#",[conversionOptions objectForKey:theString]); // I just get NULL here
//NSLog(#"the value is : %#",[conversionOptions valueForKey:theString]); // This doesn't work either, I just get NULL
You're creating a dictionary with an array as the only key and an array for its value! You want the dictionaryWithObjects:forKeys: (plural) factory, not dictionaryWithObject:forKey: (singular) so that each element of the keys array will be used as a distinct key for the respective element of the values array.
I find the dictionaryWithObjectsAndKeys: factory to be more useful most of the time, e.g.:
conversionOptions = [NSDictionary dictionaryWithObjectsAndKeys:#"1.7", #"red", #"2.8", #"blue", nil];
This is how you retrieve a string from a dictionary object
NSString * string = [dictionary objectForKey:#"stringKey"];
Use objectForKey: not valueForKey:.
Make sure conversionOptions is non-nil when you call objectForKey: (which is the right method).
And, yeah, derp -- I missed that the wrong factory method was used. You could do dictionaryWithObjects:andKeys: or do what pmjordan said said.
You absolutely must use objectForKey:, though. valueForKey: is specific to KVC.
Ok so I want to create a temporary NSDictionary from a NSDictionary of nested dictionaries, but I want to deep copy individual items(dictionaries) from the top level dictionary.
The end result is to have a filtered dictionary that i can process and discard without effecting the main dictionary.
That sounds really confusing, so how about a little code to show you what I mean, heres the function i'm working on, this is a rough coding layout, but basically complete in its path of process.
I've looked at reference books and various samples online with no joy.
Cheers,
Darren
- (void)setPricingData
{
// get selected lens option
NSDictionary *aOption = [self.lensOptionsDict objectAtIndex:self._lensOptionsIndex];
if ( aOption == nil )
return;
// get selected lens type
NSDictionary *aType = [self.lensTypesDict objectAtIndex:self._lensTypesIndex];
if ( aType == nil )
return;
// get lens option id and variation_id
NSString *option_id = [aOption valueForKey:#"id"];
NSString *option_variation_id = [aOption valueForKey:#"variation_id"];
// create temp dictionary for type pricing selection
int count = [self.lensTypesDict count];
NSMutableDictionary *aPrices = [[NSMutableDictionary alloc] initWithCapacity:count];
// cycle prices for option id and variation_id matches
for ( NSDictionary *item in self.pricesDict )
{
NSString *variation_id = [item valueForKey:#"variation_id"];
NSString *value_id = [item valueForKey:#"value_id"];
// add matches to temp dictionary
if ( [option_variation_id isEqualToString: variation_id] )
{
if ( [option_id isEqualToString: value_id] )
[aPrices addObject: item];
}
}
// get price from temp dictionary for selected lens type index
NSDictionary *price = [aPrices objectAtIndex:self._lensTypesIndex];
if ( price != nil )
{
// assign values to outlet
self.priceAndStockId = [price valueForKey:#"price"];
self.priceSelected = [price valueForKey:#"price"];
}
// release temp dictionary
[aPrices release];
}
It looks like you're mixing up dictionaries with arrays.
Arrays respond to objectAtIndex whereas dictionaries respond to objectForKeys. Remember that an array is a set of cells that you can index into, starting from 0 all the way up to [array count] - 1.
A dictionary is similar to an array, except that a hash function is used as the indexing method. This means that you need a key to get, or set, and object.
Setting an object in an NSMutableDictionary
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] init];
[myDictionary setObject:anObject forKey:aKey];
Or, you can have an array of keys and corresponding array of objects, and do:
NSDictionary *completeDictionary;
completeDictionary = [NSDictionary dictionaryWithObjects:objectArray
forkeys:keyArray count:[keyArray count]];
In either case, you must have keys for objects. This is in contrast to a regular array in which you can simply do
[myArray addObject:myObject];
To get objects from a dictionary, do
myObject = [myDictionary objectForKey:key];
To get objects from an array, do
myObject = [myArray objectAtIndex:anIntegerIndex];
Finally, your original question pertained to deep copying. To have your dictionary keep an object that won't change, ie, a deep copy, you can do the following:
Assuming I want to store a dictionary within a dictionary, and I have an associated key for the top-level dictionary, I can do the following:
I have an NSMutableDictionary, called topLevelDictionary
I have an NSDictionary, called dictionaryTwo
I have an NSString, which is my key, called myKey.
To make a deep copy of dictionaryTwo, I can do
// assuming topLevelDictionary is previously defined
[topLevelDictionary setObject:[[dictionaryTwo copy] autorelease] forKey:myKey];
In this manner topLevelDictionary will contain a copy of dictionaryTwo whereby if dictionaryTwo changes, the object in topLevelDictionary will not.
I have an array of NSDictionaries. How can I pull out the first element in the dictionary?
NSArray *messages = [[results objectForKey:#"messages"] valueForKey:#"message"];
for (NSDictionary *message in messages)
{
STObject *mySTObject = [[STObject alloc] init];
mySTObject.stID = [message valueForKey:#"id"];
stID = mySTObject.stID;
}
There is no "first" element in an NSDictionary; its members have no guaranteed order. If you just want one object from a dictionary, but don't care which key it's associated with, you can do:
id val = nil;
NSArray *values = [yourDict allValues];
if ([values count] != 0)
val = [values objectAtIndex:0];
NSDictionaries are unordered, meaning that there are not first or last element. In fact, the order of the keys are never guaranteed to be the same, even in the lifetime of a specific dictionary.
If you want any object, you can get one of the keys:
id key = [[message allKeys] objectAtIndex:0]; // Assumes 'message' is not empty
id object = [message objectForKey:key];
NSArray has a selector named firstObject that simplifies the code and makes it more readable:
id val = [[yourDict allValues] firstObject];
If yourDict is empty val will be nil, so is not necessary to check the dictionary/array size.
Simplest:
[[dict objectEnumerator] nextObject];
According to Apple, calls to allKeys or allValues incur the cost of creating new arrays:
A new array containing the dictionary’s values, or an empty array if
the dictionary has no entries (read-only)
So, an alternative option that does not incur such cost could look like this:
NSString* key = nil;
for(key in yourDict)
{ // this loop will not execute if the dictionary is empty
break; // exit loop as soon as we enter it (key will be set to some key)
}
id object = yourDict[key]; // get object associated with key. nil if key doesn't exist.
Note: If the dictionary is empty, the key will remain nil, and the object returned will also be nil, we therefore don't need special handling of the case where the dictionary is actually empty.
If someone is still looking for answer for this type of situation then can refer this:
// dict is NSDictionary
// [dict allKeys] will give all the keys in dict present
// [[dict allKeys]objectAtIndex:0] will give from all the keys object at index 0 because [dict allKeys] returns an array.
[[dict allKeys]objectAtIndex:0];
If you have NSDictionary named message,
It's pretty simple:
message[[[message allKeys] objectAtIndex:0]];
But you have to be sure (or better check) that your dictionary has at least one element.
Here is how you can check it:
if ([message allKeys] > 0) NSLog(#"%#", message[[[message allKeys] objectAtIndex:0]]);
But NSDictionary has no guaranteed order, so you probably should use this code only if your dictionary has only one element.
[UPDATE]
It's also good idea to use this if you need to get ANY element of dictionary
Try this:
NSDictionary *firstValue = [responseObject objectAtIndex:0];