2011-04-27 7 views
5

NSMutableDictionary를 사용하여 특정 클래스에 대한 설명자를 효과적으로 저장합니다. 왜냐하면 객체의 1000s 만 매우 작은 하위 집합에 포함되기 때문에 클래스의 모든 인스턴스에 설명자를 추가하는 메모리를 낭비하지 않기 때문입니다. 설명자.NSMutableDictionary에서 포인터 (ids)를 키로 사용할 수있는 명확한 방법이 있습니까?

은 불행하게도, 주어진 :

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. 

그래서 그 작동하지 않습니다.

[dict setObject:description forKey:[NSNumber numberWithInt:(int)p]]; // this is cool 

을하지만 그뿐만 아니라 추한하지만, 비표준 발생하기 쉬운 오류 때문에 :

그래서 같은의 NSNumber를 전달하여 해킹 할 수 있습니다.

이를 염두에두고이를 수행 할 수있는 명확한 방법이 있습니까?

+0

사용 NSMapTable를 제공합니다. 참조 : http : // nshipster.com/nshashtable-and-nsmaptable/ – LearnCocos2D

답변

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] 
+3

ARC가있는 iOS 6에서 NSValue를 사용하려면이 작업을 수행해야합니다. [NSValue valueWithPointer : (__ bridge const void *) (obj)]'. 그것은 그것을 캐스팅하지 않고 객체를 사용할 수 없습니다. –

+3

어떻습니까? @ ((NSInteger) obj)? – Mazyod

+1

'@ ((NSInteger) obj)'가 나를 위해 일한다. –

2

문제는 NSDictionary가 키를 복사한다는 것입니다. 클래스를 NSCopying을 구현하도록 만들거나 복사하지 않는 키 콜백을 사용하여 CFMutableDictionary을 사용합니다 (NSMutableDictionary를 사용하는 toll-free bridged이므로 작성한 후에 정확히 사용할 수 있습니다).

1

objc_setAssociatedObject/objc_getAssociatedObject을 쉽게 사용할 수 있습니다. 그것들은 here으로 묘사됩니다.

+0

클래스가 정상적으로 작동하는 방법의 제약 내에서 또는 단순히 전혀 사용하지 않는 것이 좋습니다. 내 API가 완전히 비표준 방식으로 작동해야하는 NSDictionary를 사용하는 것을 원하지 않습니다. –

+0

잘못된 대답에 응답하고 있습니까? 내 제안 NSDictionary 전혀 포함되지 않습니다. –

+0

죄송합니다. 죄송합니다. 처음으로 건너 뛰고 오해했습니다. 이것은 개선 된 부분이지만 상황에 따라 객체를 저장할 수 있기를 원하기 때문에 도움이되지 않습니다. 여러 코드가 잠재적으로 동일한 객체를 참조 할 수 있기 때문에 100 % 연관을 원하지 않습니다. 다른 코드가 잠금 단계에있는 것이 아니라 객체가 연결되어 있는지 확인할 수 있기를 원합니다. 나는 이것을 잘 설명하지 못했습니다. –

0

내 개인적인 솔루션 : 사용자 정의 클래스에서

재정 - (BOOL) isEqual:(id)object.

selfobject의 각 속성을 비교하십시오. 같을 경우 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; 
    } 
} 
+0

내 수업은 가볍지 않습니다. 복사를 전혀 원하지 않습니다. 그렇게하면 단순히 '설명'을 가질 수있는 모든 클래스에 포인터를 추가하는 것보다 비용이 많이들 것입니다. –

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 
관련 문제