我可以使用 NSPredicate 作为 NSDictionary 中的键吗
Posted
技术标签:
【中文标题】我可以使用 NSPredicate 作为 NSDictionary 中的键吗【英文标题】:Can I use NSPredicate as key in a NSDictionary 【发布时间】:2013-08-21 05:27:49 【问题描述】:假设我有两个NSPredicate
s
NSPredicate *pa = [NSPredicate predicateWithBlock:^(BOOL)(id evaluatedObject, NSDictionary *bindings)
return [evaluatedObject isKindOfClass:[TestClass class]];
];
NSPredicate *pb = [NSPredicate predicateWithBlock:^(BOOL)(id evaluatedObject, NSDictionary *bindings)
return [evaluatedObject isKindOfClass:NSClassFromString(@"TestClass")];
];
我想要的是,当我将pa
放入NSDictionary
并将其与另一个对象关联时,例如obj
,稍后当我使用pb
在字典中检查时,我会返回obj
。
它是这样工作的吗?
我看到NSPredicate
实现了NSCopying
,所以我希望它可以作为一个键。但我不确定我上面概述的情况。
【问题讨论】:
检查这个问题***.com/questions/730076/… @ValentinShamardin Non sequitur,这与这个问题无关。 【参考方案1】:NSPredicate
确实覆盖 isEqual
,但这似乎只在
非常简单的案例:
NSPredicate *pa = [NSPredicate predicateWithFormat:@"foo = 'bar'"];
NSPredicate *pb = [NSPredicate predicateWithFormat:@"foo = 'bar'"];
BOOL b = [pa isEqual:pb]; // --> YES
在这种情况下,您可以使用键 pa
将对象放入字典中并获取
使用键 pb
返回对象。
但这根本不适用于基于块的谓词,即使它们引用 同一块:
BOOL (^block)(id evaluatedObject, NSDictionary *bindings) = ^BOOL(id evaluatedObject, NSDictionary *bindings)
return [evaluatedObject isKindOfClass:[NSString class]];
;
NSPredicate *pa = [NSPredicate predicateWithBlock:block];
NSPredicate *pb = [NSPredicate predicateWithBlock:block];
BOOL b = [pa isEqual:pb]; // --> NO
即使这样可行,在您的情况下也需要两个 blocks 在谓词中被认为是相等的,但事实并非如此:
BOOL (^block1)(id evaluatedObject, NSDictionary *bindings) = ^BOOL(id evaluatedObject, NSDictionary *bindings)
return [evaluatedObject isKindOfClass:[NSString class]];
;
BOOL (^block2)(id evaluatedObject, NSDictionary *bindings) = ^BOOL(id evaluatedObject, NSDictionary *bindings)
return [evaluatedObject isKindOfClass:NSClassFromString(@"NSString")];
;
BOOL b = [block1 isEqual:block2]; // --> NO
最后发现两个具有相同body的块不相等:
BOOL (^block1)(id evaluatedObject, NSDictionary *bindings) = ^BOOL(id evaluatedObject, NSDictionary *bindings)
return [evaluatedObject isKindOfClass:[NSString class]];
;
BOOL (^block2)(id evaluatedObject, NSDictionary *bindings) = ^BOOL(id evaluatedObject, NSDictionary *bindings)
return [evaluatedObject isKindOfClass:[NSString class]];
;
BOOL b = [block1 isEqual:block2]; // --> NO
因此您可以将谓词用作字典中的键,但至少对于基于块的 谓词这没什么用。
【讨论】:
你的测试比我的要全面得多。谢谢! @yulan6248:不客气。 - 这是一个有趣的问题!【参考方案2】:是的,您可以使用任何对象作为键,只要它的类实现了NSCopying
。
【讨论】:
但它真的像我预期的那样工作吗?一个类可能实现了<NSCopying>
,但没有覆盖isEqual:
;如果NSPredicate
是这样,那么在字典中使用它是没有用的,因为只有完全相同的实例才会返回我之前设置的值。
@yulan6248 有可能,但不太可能。从概念上讲,可复制性意味着两个对象相等的明确且简单的定义。事实上,如果有人让他们的班级符合NSCopying
,但他们没有覆盖isEqual:
,他们应该被打脸。 (但是,嘿,你为什么不试试呢?)【参考方案3】:
不幸的是,它没有按我的预期工作。尽管NSPredicate
实现了NSCopying
,但谓词可以包含任意块这一事实应该很明显,几乎不可能可靠地比较两个NSPredicate
s。
在我的机器上测试,即使是用于查询字典的同一个谓词实例也不会返回之前的设置值。我的猜测是,当字典采用谓词时,它会复制它,并且因为 isEqual:
的实现对于 NSPredicate
可能只在相等的指针上返回 true,因此原始谓词实例与其副本相比也返回 false。
【讨论】:
以上是关于我可以使用 NSPredicate 作为 NSDictionary 中的键吗的主要内容,如果未能解决你的问题,请参考以下文章
核心数据。使用常量文字作为属性名称的 NSPredicate 问题
创建一个带有换行符的 NSPredicate 作为字符串的一部分