2013-11-03 2 views
0

OS X 용 이미지 편집 응용 프로그램을 만듭니다. 기본적으로 주어진 이미지와 연결된 창을 반환하는 다음 코드가 있습니다. 창을 만들지 않으면 하나를 만듭니다. 아직 이미지 :NSDictionary의 키 값이 설정 키와 동일하지 않습니다.

+(TNRWindow*)windowForImage:(NSImage*)img{ 
    static NSMutableDictionary *imageMapping; 
    static int uidCounter; 
    if(!imageMapping){ 
     imageMapping = [NSMutableDictionary dictionary]; 

    } 
    TNRWindow *window = [imageMapping objectForKey:img]; 
    if(!window){ 
     window = [[TNRWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 720) styleMask:(NSResizableWindowMask|NSTitledWindowMask|NSClosableWindowMask) backing:NSBackingStoreBuffered defer:NO]; 
     [window center]; 
     window.uid = [NSNumber numberWithInt:uidCounter++]; 
     [imageMapping setObject:window forKey:img]; 
    } 
    return window; 

} 

나는 같은 NSImage 인스턴스 그것에 연속 통화에 새로운, 다른 창을 반환이 방법을 본 적이있다. 나는 코드를 분석하고 [imageMapping setObject:window forKey:img];이 올바른 키를 설정하지 않는다는 것을 깨달았습니다. 해당 줄을 건너 뛸 때 키 값 쌍이 만들어 지지만 키는 img 개체와 다릅니다. 나는 사전 항목을 설정 한 후 여기에

(lldb) po img 
<NSImage 0x600000078fc0 Size={1311.5999999999999, 875} Reps=(
    "NSBitmapImageRep 0x6100000ba4c0 Size={1311.5999999999999, 875} 
    ColorSpace=sRGB IEC61966-2.1 colorspace BPS=16 BPP=48 
    Pixels=5465x3646 Alpha=NO Planar=NO Format=0 
    CurrentBacking=<CGImageRef: 0x6180003a31e0> CGImageSource=0x61000016c900" 
)> 

키 권리가 있습니다 : 여기

img 개체입니다

(lldb) po [[imageMapping keyEnumerator] allObjects] 
<__NSArrayM 0x618000255930>(
<NSImage 0x610000279440 Size={1311.5999999999999, 875} Reps=(
    "NSBitmapImageRep 0x6180000baca0 Size={1311.5999999999999, 875} 
    ColorSpace=sRGB IEC61966-2.1 colorspace BPS=16 BPP=48 
    Pixels=5465x3646 Alpha=NO Planar=NO Format=0 
    CurrentBacking=<CGImageRef: 0x6180003a31e0> CGImageSource=0x61000016c900" 
)> 
) 

객체 자신을, 그리고 NSBitmapImageRep들 다르지만, 배킹 CGImageRefCGImageSource은 동일합니다. 객체는 완벽하게 유효하지만, [imageMapping objectForKey:img];으로 전화하면 이미지 객체 자체가 사전에 키가 아니기 때문에 nil을 반환합니다. 이 메서드를 호출하는 다중 스레드가 없습니다. 여기서 정확히 무슨 일이 일어나고 어떻게이 문제를 해결할 수 있습니까?

당신은 NSImage 직접 구현할 수 objc_setAssociatedObject()

를 사용하여 창을 연결할 수

+1

사전 키로 이미지를 사용하는 것이 효과가있을 것이라고 상상할 수 없습니다. 당신은'isEqual'에 의존하여 당신이 정의한 이미지들에 대해 true를 반환하지만, 당신의 정의가 실제와 일치한다는 보장은 없습니다. –

+0

NSDictionary가 어떻게 작동하는지 이해하려고합니다. 이전에는 다른 객체에 대한 키를 설정할 때마다 잘 작동했습니다. 또한 C# 배경에서 사전에 키를 설정하는 것만으로 해당 개체의 주소가 추가되므로이 동작을 기대하는 것이 정상입니다. –

+1

그와 같은 스키마는 isEqual 메서드를 사용하는 것에 달려 있다는 것을 알아야합니다.이 메서드는 동등한 것으로 간주되는 동일한 개체로 감지합니다. 문자열과 같은 단순한 객체의 경우에는 생각할 필요가 없지만 이미지와 같은 것으로 작동하려면 객체 별 'isEqual' 메서드가 정의되어 있어야하며 확인하는 것과 동일한 내용을 확인해야합니다. 오브젝트 고유의'isEqual' 구현이없는 경우 (스펙에는 거기에있는 것이없는 것을 나타냅니다), isEqual는 포인터의 동일성을 간단히 체크합니다. –

답변

4

NSDictionary 복사 키 - 다음 텍스트는 문서를 통해 자주 반복되는 각 키를 복사

(사용 copyWithZone :; 키는 NSCopying 프로토콜을 준수해야합니다.) 사본이 새 사전에 추가됩니다.

키는 신원 값이 아닌 값으로 비교됩니다. 따라서 서로 다른 주소가 정확히 무슨 뜻인지 알 수 있습니다.

NSImage은 복사본과 일치하도록 isEqual:을 구현하지 않을 것입니다. 따라서 NSImage 이외의 것을 키로 사용해야합니다.

가치가 아닌 신원 확인 만하고 싶다면 NSValue을 사용하여 +valueWithNonretainedObject:을 사용할 수 있습니다.

예.

.... 
    NSValue *key = [NSValue valueWithNonretainedObject:img]; 
    TNRWindow *window = [imageMapping objectForKey:key]; 
    if(!window){ 
     ... 
     [imageMapping setObject:window forKey:key]; 
    } 

편집 : NSDictionaryCFDictionary는 무료 브리지이고, 당신이 대신 복사 키를 유지있는 NSDictionary를 만들 수있는 것이 핵심 기초 수준에서 거의 모든 물건에 대한 사용자 지정 기능을 지정할 수 있습니다. 그것은 정말로 당신이 가장 행복한 레벨에 달려 있습니다.

+0

나는 NSValue를 사용하여 트릭을했다. 예, 방금 주소를 비교해야했습니다. –

2

이 같은 NSImage에 범주, 함께 :

인터페이스 :

@interface NSImage (AssociatedWindow) 
@property (nonatomic, weak) NSWindow * associatedWindow ; // change to strong if appropriate 
@end 

구현 :

@implementation NSImage (AssociatedWindow) 
@dynamic associatedWindow ; 
-(void)setAssociatedWindow:(NSWindow*)window 
{ 
    objc_setAssociatedObject(self, kAssociatedWindowKey, window, OBJC_ASSOCIATION_ASSIGN) ; // assume you want a weak ref, otherwise use OBJC_ASSOCIATION_RETAIN_NONATOMIC 
} 

-(NSWindow*)associatedWindow 
{ 
    return objc_getAssociatedObject(self, kAssociatedWindowKey) ; 
} 

-(NSWindow*)ensureAssociatedWindow 
{ 
    NSWindow * result = self.associatedWindow ; 
    if (!result) 
    { 
     NSWindow * newWindow = // create window 
     self.associatedWindow = newWindow ; 
     result = newWindow ; 
    } 
    return result ; 
}  
@end 

이 : NSWindow * theWindow = [ theImage ensureAssociatedWindow ]

+0

내 코드가 그런 식으로 행동하는 이유는 무엇입니까? –

+1

@ 토미가 올바르게 설명한다고 생각합니다. – nielsbot

관련 문제