fast enumeration on NSDictionary fails with “[Waypoint countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance …”

StackOverflow https://stackoverflow.com/questions/2074461

Question

I have my data in a NSDictionary object where the keys are CGPoints converted to NSValues and the objects are UIColors. Here's the method I'm using to return an object from the dictionary:

- (UIColor*) getTemperatureColor2 {
    NSDictionary* temperatureColorMap = [Weather getTemperatureColorMap];   

    for(id key in temperatureColorMap) {
        CGPoint point = [key CGPointValue];
        if ( (int)roundf(self.temperature_celsius) >= (int)roundf(point.x)  ) { 
            if ( (int) roundf(self.temperature_celsius) <= (int) roundf(point.y) ) {
                return [temperatureColorMap objectForKey:key];
            }
        }       
    }

    return [UIColor blackColor];    
}

This is the getTemperatureColorMap method, implemented in this same class (Weather):

+ (NSDictionary*) getTemperatureColorMap {
    static NSDictionary* temperatureColorMap = nil;

    if (temperatureColorMap == nil) {
        temperatureColorMap = [[[NSDictionary alloc] initWithObjectsAndKeys:
                            RGB2UIColor(0x0E09EE), [NSValue valueWithCGPoint: CGPointMake(-99, -8)],
                            RGB2UIColor(0xB85FC), [NSValue valueWithCGPoint:  CGPointMake(-7, -3) ],
                            RGB2UIColor(0x0BDCFC), [NSValue valueWithCGPoint: CGPointMake(-2, 2) ],
                            RGB2UIColor(0x1BBA17), [NSValue valueWithCGPoint: CGPointMake(3, 7) ],
                            RGB2UIColor(0x45F90C), [NSValue valueWithCGPoint: CGPointMake(8, 12) ],
                            RGB2UIColor(0xF9F60C), [NSValue valueWithCGPoint: CGPointMake(13, 17) ],
                            RGB2UIColor(0xF9B20C), [NSValue valueWithCGPoint: CGPointMake(18, 22) ],
                            RGB2UIColor(0xF9780C), [NSValue valueWithCGPoint: CGPointMake(23, 27) ],
                            RGB2UIColor(0xFE3809), [NSValue valueWithCGPoint: CGPointMake(28, 32) ],
                            RGB2UIColor(0xFE0909), [NSValue valueWithCGPoint: CGPointMake(33, 99) ], nil] autorelease];
    }

    return temperatureColorMap;
}

I call getTemperatureColor2 in a for loop (going through all the waypoints), which is all in the drawRect method. A waypoint contains a weather object.

routeAnnotation.lineColor = [fromWaypoint.weather getTemperatureColor2];

When the view loads, the drawRect method is called twice (I need this for an effect). The first time everything is fine, but the second time as soon as the code reaches the fast enumeration for loop I get an exception:

2010-01-15 11:40:42.224 AppName[1601:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[Waypoint countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x856d170'

Now I have no idea how the error is in Waypoint as it's a NSDictionary that I'm iterating through. Also, I absolutely don't understand why it takes another call to drawRect for the iteration to fail!

Was it helpful?

Solution

You want to perform fast enumeration on the keys in the dictionary like this:

for(NSValue *key in [temperatureColorMap allKeys])

UPDATE
Although my suggestion makes the intent more clear, it is definitely not the cause of exception that you are seeing (I realize now that NSDictionary implements fast enumeration and it must be on the array of keys).

I am now thinking it might be a memory error since you are autoreleasing the dictionary (but the static reference to it doesn't get set to nil when it's released), but I can not reproduce the exception even running your method many times.

The only difference between my code and yours is that I changed the call to RGB2UIColor into a call to an objective-C method instead.
You didn't provide its implementation, but can I assume it is able to return a proper objective-C UIColor object?

OTHER TIPS

I thought the default array syntax for fast enumeration would automagically work for NSDictionary:

for(MyClass* instance in dictionary){  // <- this works for NSArray
    // process instance here
}

However, this seems to yield both objects (instances of MyClass) and keys from the dictionary (instances of NSString). My app was crashing because of MyClass methods being called on NSString. So I ended up doing this:

for(MyClass* instance in [dictionary allValues]){ // (as opposed to 'allKeys')
    // process instance here
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top