Ed Marty
Ed Marty

Reputation: 39700

Is there anything like an NSSet that allows retrieving by hash value?

I'm trying to create an NSDictionary that stores objects with keys based on IDs. I know I can use NSNumber objects, but why can't I just use an int instead? Is there some class that supports this? Something like an NSSet almost works, except I can't access it by it's hash value (I've overridden - (NSUInteger) hash to return the object's ID, which always unique)

I'm basically trying to turn this:

//objects is an NSMutableDictionary
- (id) objectForId:(NSUInteger)id {
  return [objects objectForKey:[NSNumber numberWithInt:id]];
}
- (void) addObject:(Object *)foo {
  [objects setObject:foo forKey:[NSNumber numberWithInt:id]];
}

into this:

//objects is an NSSet
- (id) objectForId:(NSUInteger)id {
  return [objects objectForHash:id];
}
- (void) addObject:(Object *)foo {
  [objects addObject:foo];
}

Upvotes: 2

Views: 2365

Answers (3)

Ed Marty
Ed Marty

Reputation: 39700

I ended up creating a category on NSDictionary to store objects based on int keys:

@implementation NSMutableDictionary (IntKeyDictionary)
- (void) setObject:(id)obj forId:(int)id {
  [self setObject:obj forKey:[NSNumber numberWithInt:id]];
}

- (void) removeObjectForId:(int)id {
  [self removeObjectForKey:[NSNumber numberWithInt:id]];
}

- (id) objectForId:(int)id {
  return [self objectForKey:[NSNumber numberWithInt:id]];
}
@end

Upvotes: 3

bbum
bbum

Reputation: 162712

You'll want to use the C API to NSMapTable after configuring an NSMapTable instance to use integer keys. An example:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSMapTable *mt = [NSMapTable mapTableWithKeyOptions: NSPointerFunctionsIntegerPersonality | NSPointerFunctionsOpaqueMemory
                                           valueOptions: NSPointerFunctionsObjectPersonality];

    for(NSUInteger i = 0; i<10; i++) 
        NSMapInsert(mt, (void *) i, [NSNumber numberWithInt: i]);

    for(NSUInteger j = 0; j<10; j++)
        NSLog(@"retrieved %@", (id) NSMapGet(mt, (void *) j));

    [pool drain];
    return 0;
}

Note that there appears to be a bug in NSMapTable() where it does not allow 0 to be a key. Oops.

Better documentation of the functional API to NSMapTable is requested in <rdar://problem/7228605>.

A fix for the 0 key problem is documented in <rdar://problem/7228618>

Upvotes: 11

fbrereto
fbrereto

Reputation: 35925

NSDictionary's setObject:forKey: already takes the key by id, which is what it looks like you're doing with your NSSet equivalent. What about NSDictionary is insufficient for your purposes?

Upvotes: 0

Related Questions