我正在为OS创建一个图像编辑应用程序。我有以下代码,它基本上返回与给定图像关联的窗口,如果尚未为该图像创建窗口,则创建一个窗口:
+(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对象不同。
下面是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"
)>下面是我设置字典条目后的键:
(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是不同的,但是支持CGImageRef和CGImageSource是相同的。对象似乎是完全有效的,但是当我调用[imageMapping objectForKey:img];时,它将返回nil,因为图像对象本身并不是字典中的键。没有多个线程正在调用此方法。这里到底发生了什么,我如何纠正这种行为?
发布于 2013-11-03 01:18:59
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];
}编辑:NSDictionary和CFDictionary是免费的桥接,您可以在create级别为几乎每件事物指定自定义函数,这将允许您创建一个保留键而不是复制的NSDictionary。这真的取决于你最快乐的工作水平。
发布于 2013-11-03 01:15:05
您可以使用NSImage直接将窗口与objc_setAssociatedObject()关联起来。
您可以在NSImage上使用一个类别来实现is,如下所示:
接口:
@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 ]
https://stackoverflow.com/questions/19748801
复制相似问题