Accessing objects in NSMutableDictionary by index - objective-c

To display key/values from an NSMutableDictionary sequentially (in a tableview), I need to access them by index. If access by index could give the key at that index, I could than get the value. Is there a way to do that or a different technique?

You can get an NSArray containing the keys of the object using the allKeys method. You can then look into that by index. Note that the order in which the keys appear in the array is unknown. Example:
NSMutableDictionary *dict;
/* Create the dictionary. */
NSArray *keys = [dict allKeys];
id aKey = [keys objectAtIndex:0];
id anObject = [dict objectForKey:aKey];
EDIT: Actually, if I understand what you're trying to do what you want is easily done using fast enumeration, for example:
NSMutableDictionary *dict;
/* Put stuff in dictionary. */
for (id key in dict) {
id anObject = [dict objectForKey:key];
/* Do something with anObject. */
}
EDIT: Fixed typo pointed out by Marco.

you can get an array of all the keys with the allKeys method of the dictionary; and then you can access the array by index. however, a dictionary by itself does not have an inherent ordering, so the ordering of the keys you get before and after a change to the dictionary can be completely different

Related

NSDictionary assign variable from key in loop

I've got an NSDictionary loop like this:
NSMutableDictionary *readDict = [[NSMutableDictionary alloc] initWithContentsOfFile:plist];
NSDictionary *keys = [readDict objectForKey:data]; //Dictionary
for(NSString *object in keys) {
NSData *(current object name) = [keys objectForKey:object]; //Dictionary
}
// Can I assign ^ the object name to a new NSData var as it loops?
Is it possible to assign a variable name from the object name as it loops?
Objective-C is basically C with a few extensions. In your vast knowledge of the C language, have you ever seen a way to create variables at runtime? I haven't. So if I figured out correctly what you want to do, you can't.
And what is "data"? Is it a variable containing a string? The line
NSDictionary *keys = [readDict objectForKey:data]; //Dictionary
assumes that the dictionary readDict has one key-value pair where the key is equal to the string contained in the variable data, and the value is an NSDictionary. Is that what you wanted?
Next, a for loop running over a dictionary will run over the keys in that dictionary. So in
for(NSString *object in keys)
the name "object" is badly chosen, because it is actually a key.
Usually NSDictionary will either contain keys with know values, and you'd never think of using a for-loop to access them. Or you have a dictionary that can contain any number of unknown keys and you want to process them one after the other. You wouldn't have different variables.

take nsdictionary and nsstring values from a nsdictionary

I have a function that returns an NSDictionary named data. It contains 2 objects: a NSDictionary object with the key currency_data and an NSString object with the key time.
I want to pass :
the string value with the key time to a new NSString object
the NSDictionary object with the key currency_data to a NSMutableDictionary variable.
How can I do that?
Depending on whether you use ARC. With ARC your example should work, without ARC you need to retain at least the string values.
NSDictionary *dataDict = [foo data];
NSMutableDictionary *currency_dict= [[NSMutableDictionary alloc] initWithDictionary:dataDict[#"currency_data"]];
NSString *time = [data[#"time"] retain];
What anoop-vaidy meant is I think, if you need a mutable dictionary, create that in the data call directly and pass it out. Another note: You can use your knowledge of you data structure in a better way. Instead of building a dictionary with 2 keys, use the first value ( the time string) as the key and the second (the currency dict) as the value. You can access values and keys in dictionaries quite easily
NSArray *value = dict.allValues;
NSArray *keys = dict.allKeys;

Get all keys of an NSDictionary as an NSArray

Is it possible to get all the keys from a specific NSDictionary as a seperate NSArray?
Just use
NSArray*keys=[dict allKeys];
In general, if you wonder if a specific class has a specific method, look up Apple's own documentation. In this case, see NSDictionary class reference. Go through all the methods. You'll discover many useful methods that way.
Yes it's possible. Use allKeys method:
NSDictionary *yourDictionary;
NSArray * yourKeys
yourKeys = [yourDictionary allKeys];
And if you want to get all keys and values, here's what you do:
for (NSString *key in dictionary) {
id value = dictionary[key];
NSLog(#"Value: %# for key: %#", value, key);
}

Sorting a mutable array using a dictionary key

I am trying to create a simple mutable array with a single key ("dayCounter") that I intend to use for sorting. I've read loads of examples on line, but no joy.
So I create this array. Note the first entry is a NSDictionary object. (The other objects are text)
cumArray = [NSMutableArray arrayWithObjects:[NSMutableArray arrayWithObjects:
[NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%i", dayCounter] forKey:#"dayCounter"],[[dailyArray objectAtIndex:x]objectAtIndex:0],[[dailyArray objectAtIndex:x]objectAtIndex:1],[[dailyArray objectAtIndex:x]objectAtIndex:2], nil],nil];
I save the array in a plist and everything looks great after the load.
However, when I come to sort the array, the program crashes. I have tried every combination of the following:
NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"dayCounter" ascending:YES];
[cumArray sortUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
Do I need a dictionary item to act as a key? Can I sort on the first object any easier? Any help is much appreciated.
Sometimes using too many nested expressions can obscure what's really going on. For example, the 'simple' mutable array you created actually contains a nested mutable array, rather than directly containing the dictionaries you're trying to sort.
So instead of this:
cumArray = [NSMutableArray arrayWithObjects:[NSMutableArray arrayWithObjects:
[NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%i", dayCounter] forKey:#"dayCounter"],[[dailyArray objectAtIndex:x]objectAtIndex:0],[[dailyArray objectAtIndex:x]objectAtIndex:1],[[dailyArray objectAtIndex:x]objectAtIndex:2], nil],nil];
try doing this
NSDictionary *dict1 = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%i", dayCounter]
forKey:#"dayCounter"]
NSArray *objs = [dailyArray objectAtIndex:x];
NSDictionary *dict2 = [objs objectAtIndex:0];
NSDictionary *dict3 = [objs objectAtIndex:1];
NSDictionary *dict4 = [objs objectAtIndex:2];
// Note: You might want to temporarily log the values of dict2 - 4 here to make sure they're
// really dictionaries, and that they all actually contain the key 'dayCounter'.
cumArray = [NSMutableArray arrayWithObjects:dict1, dict2, dict3, dict4, nil];
Assuming that you really have a mutable array of dictionaries, each of which contains the key dayCounter, the sort descriptor you showed in your example should work just fine.
Your setup makes no sense. You are saying yourself that only the first object in the array is a dictionary that contains the key `#"dayCounter" ("The other objects are text"). How is it supposed to be sorted if only one object contains the sort criteria?
You need to sort the array with a method, like - (NSComparisunResult)compareDict
If you have to compare 2 dictionaries and determine which one should be ordered above the other ( NSOrderedAscending ) then you need to "extend" NSDictionary:
#interface NSDictionary (SortingAdditions) {}
- (NSComparisonResult)compareTo:(NSDictionary *)other;
#end
#implementation NSDictionary (SortingAddictions)
- (NSComparisonResult)compareTo:(NSDictionary *)other
{
if( [self count] > [other count] )
{ return NSOrderedAscending; }
}
#end
This method will sort NSDictionaries according to the amount of objects that they contain.
Other values you can return here are: NSOrderedDescending and NSOrderedSame.
Then you can sort the mutable array with:
[SomeMutableArray sortUsingSelector:#selector(compareTo:)];
Keep in mind that every object in the array will need to be an NSDictionary, otherwise you will get an exception: unrecognized selector sent to instance blabla
You can do the same thing for any type of object, if the array contains both NSStrings, NSNumbers and NSDictionaries you should take a different approach

Unique keys in NSDictionary - how to check given keys are copies?

I have an NSDictionary in which I use my own classes (NSObject subclasses) as keys and would like to make sure that I do not include the same key twice. However, because NSDictionary copies its keys, if I try to check whether an object is in the dictionary, it never thinks it is.
For example,
MyClass* obj = [[MyClass alloc] init];
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
[dict setObject:someObj forKey:obj];
if ([[dict allKeys] contains:obj]) // always returns false
// obj is already in dict
else
// add obj to dict etc.
Similarly, if I want to change the object associated with this key, it seems to create a new entry.
// dict is empty
// say [obj description] gives 'MyClass : 0x1' - (impossible address?)
[dict setObject:someObj forKey:obj];
// dict: { 'MyClass : 0x2' = someObjDesc }
[dict setObject:someOtherObj forKey:obj];
// dict: { 'MyClass : 0x2' = someObjDesc , 'MyClass : 0x3' = someOtherObjDesc }
Also, this same thing leads to not being able to access the items in the dictionary from the original object
[dict setObject:someObj forKey:obj];
[dict objectForKey:obj]; // returns null
So, as far as the uniqueness is concerned, would I be best off keeping track of the keys in a separate array or is there a better way of doing this.
I considered implementing an isEqual method based on a unique variable (such as a name) but didn't think that was the Right Thing to do.
Background (in case it turns out that maybe I'm just using the wrong thing entirely):
I want to keep track of information about a group of people going to different places. So each person at each place has some info. What I've done is used nested dictionaries so the key to the main dictionary is a Person object and the object another dictionary. This latter dictionary has key Place and info as the object. I think this is Java syntax but something like > (the array holds the info). I want to be able to add a Person only if the don't already exist, add a Place (for each person), change the array.
Any help on any of this would be greatly appreciated!
You should always use NSStrings as keys for dictionaries, especially if you are new at objective-C. There are a few things that I can see you are doing wrong with your current implementation - you would need to read up on key requirements for NSDictionaries.
You can do what you want with strings as keys - person's name, etc.
The objects in a dictionary have all the info about a certain person:
NSDictionary* personsInfo = [mainDict objectForKey:#"Jane Smith"];
NSString* addressLine1 = [personsInfo objectForKey#"addressLine1"];
--Tom
The simple answer would be to make it so that the MyClass doesn't actually copy anything.
That would be something like changing:
- (id) copyWithZone:(NSZone *)zone {
MyClass * foo = (MyClass *)[super copyWithZone:zone];
[foo configureCopy];
return foo;
}
To:
- (id) copyWithZone:(NSZone *)zone {
return [self retain];
}