4

我有一个NSSet包含数千个NSValue对象(包装CGPoints)。我想很快找到给定的CGPoint值是否存在于NSSet. 在我看来member:, an 的方法NSSet可能在这里完成工作,除了它使用isEqual:. NSValue对象使用isEqualToValue:,所以当我执行代码时:

[mySet member:valueToCheck];

它实际上导致 Xcode 崩溃。

1) 有什么方法可以使用自定义相等检查来使其适用于NSValue对象吗?

2)这甚至是最好的方法吗(即首先member:足够快)?场景是我有一个NSSet包含大量表示屏幕(iPad)上像素的点。稍后我需要以每秒数千个点来轰炸该集合,以查看它们是否存在于集合中。为了实现这一点,我的方法似乎很粗糙。我考虑过创建一个巨大的二维位数组,每个索引代表屏幕上的一个像素。一旦我知道我正在测试的点,我就可以直接跳到数组中的那个点并检查 1 或 0 ......这听起来更好还是更糟?

谢谢

4

5 回答 5

10

你能把它变成一个简单的可重现案例吗?例如,我刚刚尝试过:

NSValue *v = [NSValue valueWithCGPoint:CGPointMake(1, 1)];
NSSet *s = [NSSet setWithObject:v];
NSLog(@"%@", [s member:[NSValue valueWithCGPoint:CGPointMake(1, 1)]]);

但它工作得很好。

编辑

-isEqual:不是问题:

NSValue *v1 = [NSValue valueWithPoint:NSMakePoint(1, 1)];
NSValue *v2 = [NSValue valueWithPoint:NSMakePoint(1, 1)];
NSLog(@"%d", [v1 isEqual:v2]); //logs "1"

-hash不是问题:

NSLog(@"%d", ([v1 hash] == [v2 hash])); //logs "1"

它们是不同的对象:

NSLog(@"%d", (v1 != v2)); //logs "1"

问题出在您的代码中。尝试清洁和重建。

于 2011-04-19T16:27:05.560 回答
1

回答不。2:

我不知道 NSSet 是如何在内部实现的,但考虑到您知道您正在存储点(使用 X 和 Y),我认为您最好实现自己的分区算法。如果你说你有数千个点,我个人会选择我自己的实现而不是 NSSet。

为每个像素存储巨大的二维数组可能是最快的方法,但它会在内存消耗方面杀死你。你需要一些快速但又轻巧的东西。

那里有很多算法,您可以通过在维基百科或谷歌上搜索“空间分区算法”来找到它们。这还取决于您的编程技能,以及您愿意为此投入多少时间。

例如,一个非常简单的方法是实现一个四叉树,首先将屏幕(或区域)分成 4 个相等的部分。然后,如果需要以及在哪里需要,您也可以将该特定单元格分为 4 个部分。你这样做,直到每个单元格包含足够少的点,这样你就可以暴力测试所有这些点。你可以在 wiki 上找到一个很好的描述:http ://en.wikipedia.org/wiki/Quadtree

希望这可以帮助,

于 2011-04-19T16:24:05.933 回答
1

[mySet member:valueToCheck]不应该崩溃。当我在这里尝试时, NSValueisEqual:工作正常,实际上可能会isEqualToValue:在给定另一个 NSValue 进行比较时调用。真的valueToCheck是 NSValue,还是 CGPoint?

没有办法覆盖NSSet的默认哈希和比较方法。但是 NSSet 是免费桥接的CFSetRef,您可以在那里轻松地指定自定义散列和比较方法:

CFSetCallBacks callbacks = kCFTypeSetCallBacks;
callbacks.equal = customEqualFunction;
callbacks.hash = customHashFunction;
NSMutableSet *set = (NSMutableSet *)CFSetCreateMutable(NULL, 0, &callbacks);

这些函数的约束可能与 NSObjecthashisEqual:方法的约束相同,任何相等的都必须具有相同的哈希值。和的 C 风格原型在此处customEqualFunction此处customHashFunction进行了描述。

于 2011-04-19T16:36:02.013 回答
-1

一种解决方案是子类化NSSet并覆盖member:以进行自己的比较。然后你自己的比较可以简单的调用isEqualToValue:。查看NSSet文档中的子类化说明。

另一种方法是NSValue向该 implements添加一个类别isEqual:。在这种情况下,我更喜欢子类化,因为它是一个更受约束的解决方案。

于 2011-04-19T16:17:02.887 回答
-1

这不仅仅是 的问题-isEqual:,您也可能对-hash方法有问题。如果您想使用 NSSet,您可能应该创建一个包装 CGPoint 的自定义类。 -isEqual:然后是微不足道的,-hash可以通过组合两个坐标的位然后将它们视为 NSUInteger 的某种方法来实现。

您还需要实现协议,如果您的点是不可变的(只需保留并返回 self in ) NSCopying,这也是微不足道的。-copyWithZone:

于 2011-04-19T16:30:39.660 回答