views:

88

answers:

2

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!

A: 

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

Tom Andersen
I thought that was the difference between a key and a value (_should_ I use values instead then?). Would you say using the names as the keys/values and then having separate dictionaries mapping the names to the objects would be a better implementation? Thank you for taking the time to answer.
mmdeas
Just realised that it's always a key and that it was objects and values of which there were two... Just reading the Key-Value Coding Fundamentals to figure out the difference...
mmdeas
I think I've managed to re-design my data structures based on what you said and what that prompted me to read. Thanks.
mmdeas
A: 

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];
}
Dave DeLong
Ah. Even having written the code which created the new object as a copy I hadn't considered that. Could that get problematic if the object were mutable?
mmdeas
Thank you for this answer as it linked up those separate parts in my mind and helped me understand the overall process better which I'm sure will be helpful in the future.
mmdeas