Reputation: 449
The title pretty much says it all. I want to create an NSMutableDictionary where I use UIImageViews to look up boolean values. Here's what it looks like:
My .h file:
@interface ViewController : UIViewController{
UIImageView *image1;
UIImageView *image2;
NSMutableDictionary *isUseable;
}
@property (nonatomic, retain) IBOutlet UIImageView *image1;
@property (nonatomic, retain) IBOutlet UIImageView *image2;
@property (nonatomic, retain) NSMutableDictionary *isUseable;
My .m file:
@synthesize image1, image2;
@synthesize isUseable
- (void)viewDidLoad
{
isUseable = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@NO, image1,
@NO, image2,nil];
}
-(void)runEvents{
if(some condition){
[isUseable setObject:@YES forKey:(id)image1];
}
//Use it later:
if(isUseable[image1]){
//Do stuff
}
}
It compiles but when I run it I get an uncaught exception 'NSInvalidArgumentException', reason: '-[UIImageView copyWithZone:]: unrecognized selector sent to instance.
I'm guessing that the problem lies with the fact that the NSDictionary class copies its keys. Is there a way to get a dictionary working in this case? If not, how should I set up a lookup like the one I want? Any ideas / suggestions?
Upvotes: 1
Views: 946
Reputation: 17902
Depending on how your object is managed you may be able to use its address in memory as a key (This applies to both UIImageView or UIImage since the general discussion on this question seems to revolve around either/or):
myDictionary[@((intptr_t)myObject)] = myValue;
Upvotes: 0
Reputation: 17902
Get the raw data from the image (not a re-rendered PNG or JPG representation) and then run it through built in common-crypto to get SHA256 of the data, this will be your key.
Other answers suggest using the built in instance property .hash
but it is prone to collision, and they end up happening frequently (We experienced a string collision in one of our apps and it caused a severe bug).
#include <CommonCrypto/CommonDigest.h>
-(NSString *)keyFromImage:(UIImage *)image {
NSData *imageData = (__bridge NSData *)CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
unsigned char result[CC_SHA256_DIGEST_LENGTH];
CC_SHA256((__bridge const void *)imageData, (CC_LONG)imageData.length, result);
NSMutableString *imageHash = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH*2];
for(int i = 0; i<CC_SHA256_DIGEST_LENGTH; i++) {
[imageHash appendFormat:@"%02x",result[i]];
}
return imageHash;
}
Upvotes: 0
Reputation: 3042
rmaddy said it pretty right: an NSDictionary
must conform to the NSCopying
protocol and UIImage
does not.
I recommend to use @(image.hash)
as dictionary key. It's like a fingerprint of UIImage
.
Upvotes: 3
Reputation: 7720
Keys in NSDictionaries
have to conform to NSCopying
and UIImageView
doesn't.
You will have to find a different key, or you could extend UIImageView
to conform to NSCopying
. See this answer on SO for how to do it with a UIImage
.
Upvotes: 1
Reputation: 318904
Yes, the problem is that keys in an NSDictionary
must conform to the NSCopying
protocol and UIImage
does not.
One solution would be to give each image a unique tag. Then use the image's tag as the key (after wrapping it in an NSNumber
).
- (void)viewDidLoad {
isUseable = [ @{ @(image1.tag) : @NO, @(image2.tag) : @NO } mutableCopy];
}
-(void)runEvents {
if(some condition) {
[isUseable setObject:@YES forKey:@(image1.tag)];
}
//Use it later:
if(isUseable[@(image1.tag)]) {
//Do stuff
}
}
Just add the code to see each image's tag
property.
Upvotes: 4