Objective-C:使用自定义对象键从NSMutableDictionary获取值

Objective-C:使用自定义对象键从NSMutableDictionary获取值,objective-c,object,dictionary,nsmutabledictionary,Objective C,Object,Dictionary,Nsmutabledictionary,我一直使用带有字符串的词典作为键,而web/books/等上的示例几乎都是相同的。我想我会尝试用一个自定义对象作为密钥。我已经阅读了“copyWithZone”方法的实现,并创建了以下基本类: @interface CustomClass : NSObject { NSString *constString; } @property (nonatomic, strong, readonly) NSString *constString; - (id)copyWithZone:(NSZ

我一直使用带有字符串的词典作为键,而web/books/等上的示例几乎都是相同的。我想我会尝试用一个自定义对象作为密钥。我已经阅读了“copyWithZone”方法的实现,并创建了以下基本类:

@interface CustomClass : NSObject
{
    NSString *constString;
}

@property (nonatomic, strong, readonly) NSString *constString;

- (id)copyWithZone:(NSZone *)zone; 

@end

@implementation CustomClass

@synthesize constString;

- (id)init
{
    self = [super init];
    if (self) {
        constString = @"THIS IS A STRING";
    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone
{
    CustomClass *copy = [[[self class] allocWithZone: zone] init];
    return copy;
}

@end
现在,我尝试使用一个简单的字符串值添加其中一个对象,然后将字符串值返回到控制台:

CustomClass *newObject = [[CustomClass alloc] init];
NSString *valueString = @"Test string";
NSMutableDictionary *dict =
[[NSMutableDictionary alloc] initWithObjectsAndKeys:valueString, newObject, nil];

    NSLog(@"Value in Dictionary: %@", [dict objectForKey: newObject]);
    // Should output "Value in Dictionary: Test string"

不幸的是,日志显示为空。我很确定我错过了一些非常明显的东西,我觉得我需要另一双眼睛。

我认为你的类需要定义:

- (BOOL)isEqual:(id)anObject

这就是字典可能用来确定您的密钥是否等于字典中已使用的密钥的方法。

NSDictionary
密钥对象使用三种方法:

  • -(整数)散列
  • -(BOOL)isEqual:(id)other
  • -(id)copyWithZone:(NSZone*)区域
默认的
NSObject
实现
hash
isEqual:
仅使用对象的指针,因此当通过
copyWithZone:
复制对象时,副本和原始对象不再相等

你需要的是这样的东西:

@implementation CustomClass

-(NSUInteger) hash;
{
    return [constString hash];
}

-(BOOL) isEqual:(id)other;
{
    if([other isKindOfClass:[CustomClass class]])
        return [constString isEqualToString:((CustomClass*)other)->constString];
    else
        return NO;
}
- (id)copyWithZone:(NSZone *)zone
{
    CustomClass *copy = [[[self class] allocWithZone: zone] init];
    copy->constString = constString; //might want to copy or retain here, just incase the string isn't a constant
    return copy;
}

@end
从文档中找到这一点有点困难。告诉您有关
isEqual:
NSCopying

在字典中,键是唯一的。也就是说,一个房间里没有两个钥匙 单个字典是相等的(由isEqual:确定)。一般来说 密钥可以是任何对象(只要它符合NSCOPY 协议(见下文),但请注意,当使用键值编码键时 必须是字符串(请参阅“键值编码基础”)

如果您看一下,它会告诉您关于
散列

如果两个对象相等,则它们必须具有相同的哈希值。这 最后一点特别重要,如果您在 子类,并打算将该子类的实例放入 收集确保在子类中也定义了hash


什么是返回方法
allKeys
?是的,如果我有需要复制的ivar,我会在那里放一个retain。为了简单起见,我只是在类中放置了一个常量只读字符串,以获得字典键的对象概念。但奇怪的是,似乎明显的问题是我没有实现字典所需的方法。因为我不遵守任何协议,我怎么知道我需要实现什么方法才能让它工作(除了执行stackoverflow搜索)。通过这种方式,我可以在将来自己解决类似的问题。我已经用苹果文档中的一些链接/引用更新了答案。谢谢。我只有两个问题。1) 我是否需要将实现中的这些方法添加到接口文件中?为什么?2) 看起来hash和equal方法只是基于该常量字符串进行测试。因此,如果我要将其用于一个完整的类,我将如何更新hash方法?我假设对于isEqual,我必须彻底测试每个ivar,以确保两个对象实际上相等。从技术上讲,您不需要在接口中声明方法,因为isEqual:
哈希
复制
都来自
NSObject
。不过,最好声明您符合
NSCopying
。首先确定是什么使两个对象相等(如果需要,可以是每个ivar),然后实现
isEqual:
。接下来,实现
hash
,以便相同的对象也具有相同的hash,但不同的对象具有不同的hash。一种简单的方法是对
isEqual:
中使用的IVAR哈希进行异或运算。当对象位于
NSDictionary
中时,哈希值不应更改,因此键对象通常是不可变的。