0

This is probably a rather basic problem, but try as I might I can't find the reason that causes it.

I wrote the following code:

    NSMutableDictionary * myDictionary = [[NSMutableDictionary alloc] init];
    NSMutableArray * values = [[NSMutableArray alloc] init];

    for (int i=0; i<10; i++) {

        // create an object that can become a key in an NSDictionary
        CustomObjectAdoptingNSCopy * someKey = [[CustomObjectAdoptingNSCopy alloc] init];

        // create a random value that will become an object for myDictionary ...
        int someValue = rand()%10;

        // ... and which also gets to be an object in the values array, provided it isn't already stored there
        if ([values indexOfObject:[NSNumber numberWithInt:someValue]]==NSNotFound)
            [values addObject:[NSNumber numberWithInt:someValue]];

        // now associate someValue with someKey in myDictionary
        [myDictionary setObject:[NSNumber numberWithInt:someValue] forKey:someKey];
    }

    // read the data in myDictionary enumerating the NSArray values
    for (NSNumber * aValue in values){
        NSArray * objectsForValue = [myDictionary allKeysForObject:aValue];
        // now the data from objectsForValue are being used ...
    }

The problem manifests when objectsForValue is empty, which does not happen all the time but regularly. If I am not very much mistaken this is logically impossible unless [NSNumber numberWithInt:someValue] gets interpreted as NSNull when added as Object to myDictionary, while the same expression gets treated as an object when it is being added to the NSArray values.

And logging myDictionary I noticed that this is indeed what's happening. Can anybody explain to me why?

magnus1969
  • 137
  • 6
  • 2
    Why are you making an array and a dictionary? Why not just set the object for key and then enumerate over the dictionary? – Peter Foti Nov 20 '13 at 21:27
  • 6
    Show the logged dictionary. There's *nothing* here that will magically introduce `NSNull` objects, which are not the same as `nil`. Show the code for how `CustomObjectAdoptingNSCopy` implements copying *and* equality. – Ken Thomases Nov 20 '13 at 21:41
  • 1
    There are many, many more plausible explanations than "an NSNumber is getting magically turned into NSNull". For example, your dictionary could be getting modified behind your back, you might have a typo in the original code that is not present in this obviously fake example, etc. It's hard to say for certain without the actual code, but if I were you, I would investigate much more thoroughly before jumping to a conclusion like magical NSNulls. – Chuck Nov 20 '13 at 21:46
  • @Ken Thanks for the comment! I checked the implementation of the NSCopying protocol. I allocate a new instance in `copyWithZone` and return it - as I did in similar situations more than once without getting into trouble. But I found, that if I `return self` and leave the allocation to an implementation of `mutableCopyWithZone` my code works fine. I can't say that I really understand why that is, but the import thing is, my app does not crash anymore. – magnus1969 Nov 21 '13 at 21:09

1 Answers1

1

If you haven't overridden -isEqual: and -hash, then copies of your CustomObjectAdoptingNSCopy don't equal each other. NSObject's default implementation of equality is object identity. Since NSDictionary copies the keys but copies don't equal the original, you can't retrieve anything from the dictionary unless you ask it for its keys and use those. The originals won't work.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154