我正在使用NSMutableDictionary来存储有效的某些类的描述符,因为我宁愿不浪费将描述符添加到每个类的实例的内存,因为只有1000个对象的非常小的子集将具有描述符。
不幸的是,给定:
MyClass* p = [MyClass thingy];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSString* description = @"blah"; //does this work? If not I'm just simplifying for this example.
[dict setObject:description forKey:p]; // BZZZZT a copy of p is made using NSCopying
MyClass* found = [dict objectForKey:p]; //returns nil, as p becomes a different copy.
所以这不起作用。
我可以通过传递NSNumber来破解它:
[dict setObject:description forKey:[NSNumber numberWithInt:(int)p]]; // this is cool
但这不仅是丑陋的,而且因为它是非标准的而容易出错。
考虑到这一点,有没有一种干净的方法来做到这一点?
答案 0 :(得分:7)
NSValue根据NSValue Class Reference确认NSCopying。因此,您可以使用NSValue实例作为密钥。
使用+valueWithPointer:将指针值包起来。
NSString* foo = @"foo";
id bar = @"bar";
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setObject:@"forKey:foo" forKey:foo];
[dict setObject:@"forKey:bar" forKey:bar];
[dict setObject:@"forKey:[NSValue... foo]" forKey:[NSValue valueWithPointer:foo]];
[dict setObject:@"forKey:[NSValue... bar]" forKey:[NSValue valueWithPointer:bar]];
NSLog(@"%@", [dict objectForKey:foo]);
NSLog(@"%@", [dict objectForKey:bar]);
NSLog(@"%@", [dict objectForKey:[NSValue valueWithPointer:foo]]);
NSLog(@"%@", [dict objectForKey:[NSValue valueWithPointer:bar]]);
给出
2013-01-24 04:42:14.051 a.out[67640:707] forKey:foo
2013-01-24 04:42:14.052 a.out[67640:707] forKey:bar
2013-01-24 04:42:14.053 a.out[67640:707] forKey:[NSValue... foo]
2013-01-24 04:42:14.053 a.out[67640:707] forKey:[NSValue... bar]
答案 1 :(得分:2)
您的问题是NSDictionary复制其密钥。要么让你的类实现NSCopying,要么使用带有不复制的密钥回调的CFMutableDictionary(它是toll-free bridged和NSMutableDictionary,所以你可以在创建后使用它完全相同。)
答案 2 :(得分:1)
您可能会发现使用objc_setAssociatedObject
/ objc_getAssociatedObject
更容易。他们被描述为here。
答案 3 :(得分:0)
我的个人解决方案:
覆盖自定义类中的- (BOOL) isEqual:(id)object
。
在此方法中,比较self
和object
中的每个属性。如果它们相同,请返回YES
我不确定你是如何实现- (id) copyWithZone:(NSZone *)zone
方法的,但对于我的测试项目,它对我来说很好。
附件:
- (id) copyWithZone:(NSZone *)zone{
testObject *copy = [[testObject allocWithZone:zone] init];
NSString *tempCopyString = [NSString stringWithString:self.string]
copy.string = tempCopyString;
return copy;
}
- (BOOL) isEqual:(id)object{
testObject *newObject = (testObject*)object;
if ([newObject.string isEqualToString:object.string]) {
return YES;
}
else {
return NO;
}
}
答案 4 :(得分:0)
由于这是一个经常出现的问题,我创建了以下类来将对象关联到其他对象而不复制该关键字。身份是根据关键对象地址确定的。 它是NSMutableDictionary的子类,因此该类的所有方法都可用。
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