As this is a problem that can occur often, I have created the following class to associate objects to other objects without copying of the key. Identity is determined on the key object address.
It's a subclass of NSMutableDictionary, so all methods of that class are available.
ObjectMap.h
//
// ObjectMap.h
//
// Created by René Dekker on 07/03/2012.
// Copyright (c) 2012 Renevision.
//
#import <Foundation/Foundation.h>
@interface ObjectMap : NSMutableDictionary
+ (ObjectMap *) objectMap;
- (bool) containsObject:(id)aKey;
// use the following instead of setObject:forKey: in IOS 6, to avoid warnings about NSCopying
- (void) setObject:(id)anObject forObjectKey:(id)aKey;
@end
ObjectMap.m
//
// ObjectMap.m
//
// Created by René Dekker on 07/03/2012.
// Copyright (c) 2012 Renevision.
//
#import "ObjectMap.h"
#import <CoreFoundation/CoreFoundation.h>
@interface ObjectMapEnumerator : NSEnumerator
@end
@implementation ObjectMapEnumerator {
NSUInteger size;
NSUInteger currentIndex;
id *keysArray;
}
- (NSArray *) allObjects
{
return [NSArray arrayWithObjects:keysArray count:size];
}
- (id) nextObject
{
if (currentIndex >= size) {
return nil;
}
return keysArray[currentIndex++];
}
- (id) initWithDict:(CFDictionaryRef)dict
{
if (!(self = [super init])) {
return nil;
}
size = CFDictionaryGetCount(dict);
keysArray = malloc( size * sizeof(id) );
currentIndex = 0;
CFDictionaryGetKeysAndValues(dict, (const void **)keysArray, NULL);
return self;
}
- (void) dealloc
{
free(keysArray);
[super dealloc];
}
@end
@implementation ObjectMap {
CFMutableDictionaryRef theDictionary;
}
- (void) setObject:(id)anObject forKey:(id)aKey
{
CFDictionarySetValue(theDictionary, aKey, anObject);
}
- (void) setObject:(id)anObject forObjectKey:(id)aKey
{
CFDictionarySetValue(theDictionary, aKey, anObject);
}
- (id) objectForKey:(id)aKey
{
return CFDictionaryGetValue(theDictionary, aKey);
}
- (void) removeObjectForKey:(id)aKey
{
CFDictionaryRemoveValue(theDictionary, aKey);
}
- (void) removeAllObjects
{
CFDictionaryRemoveAllValues(theDictionary);
}
- (bool) containsObject:(id)aKey
{
return CFDictionaryContainsKey(theDictionary, aKey);
}
- (NSUInteger) count
{
return CFDictionaryGetCount(theDictionary);
}
- (NSEnumerator *)keyEnumerator
{
return [[[ObjectMapEnumerator alloc] initWithDict:theDictionary] autorelease];
}
#pragma - Object Life Cycle
static void dictionaryRelease(CFAllocatorRef allocator, const void* value) {
if (0 != value) {
CFRelease(value);
}
}
static const void *dictionaryRetain(CFAllocatorRef allocator, const void* value) {
if (0 != value) {
return CFRetain(value);
}
return 0;
}
static CFDictionaryKeyCallBacks callbacks = { 0, &dictionaryRetain, &dictionaryRelease, &CFCopyDescription, NULL, NULL };
- (id) init
{
if (!(self = [super init])) {
return nil;
}
theDictionary = CFDictionaryCreateMutable(NULL, 0, &callbacks, &kCFTypeDictionaryValueCallBacks);
return self;
}
- (void) dealloc
{
CFRelease(theDictionary);
[super dealloc];
}
+ (ObjectMap *) objectMap
{
return [[[ObjectMap alloc] init] autorelease];
}
@end