NSDictionary objectForKey answere randomly - iphone

I have a NSMutableDictionary, and my keys are objects (and the class implement the NSCopying protocol).
I add a value in the dictionary associated to a key, then, when I call the objectFoKey: method for the key which is in the dictionary, randomly, sometimes the method call "isEqual" and the key is found, and sometimes, the method "isEqual" is not called and the key is not found.
I can understand I do something wrong and the key is not found, but why sometimes the key is found but not always ?
Thank you very much if you have some hints to fix that problem, it becomes to make me crazy.

Oups, ok, I found my mistake:
I must implement the hash method, that I didn't do.

Related

Check for iVar's Names with respect to NSDictionary keys

I am parsing the values of Json object to my data model, and I am trying to figure out if there is any way to compare the name of the iVar's set for are the same with respect to dictionary keys. I am sure there is a good way to do that, but just can't find the method somehow.
Thanks.
It's a little hard to tell what you're asking, but I think you want Key-Value Coding. In particular, setValuesForKeysWithDictionary: will let you pass a dictionary of property or ivar names and set them for you.

What classes can be used as a key in NSDictionary?

Can we use only NSString objects as key in an NSDictionary? How do we know which objects can be used and which cannot?
From the documentation:
In general, a key can be any object (provided that it conforms to the NSCopying protocol), but note that when using key-value coding the key must be a string (see “Key-Value Coding Fundamentals”).
So you can use anything copyable besides strings, but they'll be problematic with KVC. I just use strings for keys to keep things safe, consistent and simple.
You can use anything that conforms to NSCopying. That is, you can use id - type objects, as long as they conform to NSCoding protocol.
In instances where the key is NSString, then isEqualToString: is called for retrieval. Otherwise, isEqual: is called on the object to determine whether the key matches the requested key.
The key (and value for that matter) cannot be nil or NULL. They can, however, be [NSNull null].

NSMutableDictionary key values

is it true that the key values for NSMutableDictionary can only be strings?
I was trying to use objects, but I am getting a warning.
From the docs:
In general, a key can be any object
(provided that it conforms to the
NSCopying protocol—see below), but
note that when using key-value coding
the key must be a string (see
Key-Value Coding Fundamentals).
What warning are you getting?
You can use any object, but the object must implement -[NSObject hash], -[NSObject isEqual:], and the NSCopying protocol.
If you take a look at header file of NSMutableDictionary, the add function can take id as the key:
- (void)setObject:(id)anObject forKey:(id)aKey;
- (void)removeObjectForKey:(id)aKey;
So you can use virtually anything as the key and value.

Do constants always keep the same value?

I've been reading that when conforming to the NSCoding protocol and implementing the methods like -encodeWithCoder:, and encoding objects with i.e.
[coder encodeObject:self.someObject forKey:kSomeConstantToIdentifyFields];
this constant is used to keep track of that object. So later, with help of that constant, the appropriate "field" or whatever can be mapped to that object again (in this case an property).
But: Isn't this funny constant actually a random value when defined like this?
#define kSomeConstantToIdentifyFields #"fieldFooBar"
How does the system manage it to always assign the same value to that constant? Or did I get some stuff about this constants wrong? Is the value actually "fieldFooBar" and not some random number?
The key is a string - a name, if you will - that identifies a field in a dictionary. In this case, the dictionary is what will be written, or read from the archive that was created via the NSCoding protocol.
When you define the key like that, it's not necessarily constant, because it could be changed at some point (but only deliberately, not randomly by the system). As long as you don't change the #"fieldFooBar" string, it'll stay like that throughout the life of the program.
Keys are defined like this, not to be constant, but to be able to flag up compiler warnings and errors, such as spelling mistakes.
If you define the key once, and then refer to it by it's preprocessor symbol, if you mispell it, the compiler will throw an error saying it can't find that symbol. If you just used a string in it's place each time, then the compiler wouldn't know and wouldn't be able to warn you about it. Then you'd be on your own trying to figure out why your field isn't being decoded - because you're asking for the wrong key name.
Before your application compiles, a pre-compilation process occurs. The #define key value directive tells the pre-compiler "whenever you see key, replace it with value". It's not only that they're constants; it's as if you wrote #"fieldFooBar" all over your application yourself.
The reason not to do it yourself is to avoid mistakes, and I think Jasarien gave a great explanation for that in his answer.
Better way to define string constants is to use
static NSString *kSomeConstantToIdentifyFields = #"fieldFooBar";
That would same you some memory. Also, I suppose that isEqual: chects the object pointer, so having all constants point to one place is good.
Do constants always keep the same
value?
I believe that's why they're called constants. ;o)

How to store object + string pairs without retaining the objects, and what kind of storage to use?

I am implementing a class that has to store arbitrary objects together with a string. i.e.
myUIViewObject, #"that's a nice view"
myUIViewController, #"not really special"
myOtherObject, #"very important one"
this list can be extended and modified at any time, so I thought about using NSMutableDictionary here. But I am not really sure...
The object should be the key, i.e. I want to find easily the matching string for myUIViewController or myOtherObject when I ask for it like so:
- (NSString*)checkObjNoteStringForObject:(id)anyObjectInList;
The other problem is, that when an object gets added to that "list", I don't want it to be retained because of that. NSMutableDictionary retains it's contents, right? Could I just send a -release afterwards to undo this unwanted behaviour, and when removing from the list just sending -retain before doing so? Or is there a more elegant way?
What do you suggest? Thanks # all!
If your dictionary key is not retained, once it is deallocated accesses to the dictionary will lead to undefined behaviour (in practice, they'll crash if a lookup happens to hit that dictionary element). To do what you want, you need a strategy to remove the objects from the dictionary when necessary.
If you do have one – for instance, overriding the objects’ -dealloc and removing them from there – you can do what you want using +[NSValue valueWithNonretainedObject:]. The NSValue will refer to your object without retaining it, and the dictionary will copy the NSValue (keys are copied, not retained). Just remember to create an NSValue for each time you want to look something up in the dictionary; a helper function or method is a good idea.