NSSet - 检查 NSValue 是否相等的成员

发布于 2024-11-02 07:40:59 字数 695 浏览 3 评论 0原文

我有一个 NSSet ,其中包含数千个 NSValue 对象(包装 CGPoints)。我想快速查找 NSSet 中是否存在给定的 CGPoint 值。在我看来,NSSetmember: 方法可以完成这里的工作,只不过它使用 isEqual: 检查相等性。 NSValue 对象使用 isEqualToValue:,因此当我执行代码时:

[mySet member:valueToCheck];

它实际上会导致 Xcode 崩溃。

1)是否有某种方法可以使用自定义相等性检查来使其适用于 NSValue 对象?

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

谢谢

I have a NSSet containing many thousands of NSValue objects (wrapping CGPoints). I would like to very quickly find if a given CGPoint value exists in the NSSet. It seems to me that the member: method of an NSSet might do the job here, except that it checks for equality using isEqual:. NSValue objects use isEqualToValue:, and so when I execute the code:

[mySet member:valueToCheck];

it actually causes Xcode to crash.

1) Is there some way to use a custom equality check to make this work for NSValue objects?

2) Is this even the best approach (i.e. is member: quick enough in the first place)? The scenario is that I have a NSSet containing a large number of points representing pixels on the screen (iPad). Later on I need to bombard that set with many thousands of points per second to see if they exist in the set. My approach seems crude for achieving this. I thought about creating something like a huge 2-dimensional bit array, with each index representing a pixel on screen. Once I know the point I'm testing for, I can just jump straight to that point in the array and check for a 1 or 0... does this sound better or worse?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

野侃 2024-11-09 07:40:59

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

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

但效果很好。

edit

-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"

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

Can you get this to a simple reproducible case? For example, I just tried:

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

But it works just fine.

edit

-isEqual: is not the problem:

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

-hash is not the problem:

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

They are different objects:

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

The problem is in your code. Try cleaning and rebuilding.

つ低調成傷 2024-11-09 07:40:59

回答否。 2:

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

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

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

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

希望这有帮助,

To answer no. 2:

I don't know how NSSet is implemented internally, but considering that you know you are storing points (with X and Y), I think you would be better by implementing your own partitioning algorithm. Personally I would choose my own implementation over NSSet if you say you have thousands of points.

Storing huge 2-dimensional arrays for each pixel, would probably be the fastest way, but it will kill you in terms of memory consumption. You need something fast, but also lightweight.

There are a lot of algorithms out there and you can find them by searching "spatial partitioning algorithms" on wikipedia or google. It also depends on your programming skills, and how much time you are willing to invest in this.

For example, a pretty simple one would be to implement a quad-tree, where you start by diving your screen(or area) in 4 equal parts. Then if and where is needed, you divide that specific cell also in 4 parts. And you do this until each cell contains a small enough number of points so that you can brute-force test all of them.
You can find a very good description on wiki: http://en.wikipedia.org/wiki/Quadtree

Hope this helps,

油饼 2024-11-09 07:40:59

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

无法覆盖 NSSet 的默认哈希和比较方法。但 NSSet 与 CFSetRef,您可以轻松地在其中指定自定义散列和比较方法:

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

对这些函数的约束大概与 NSObject 的 hash 上的约束相同和 isEqual: 方法,任何相等的东西都必须具有相同的哈希值。 customEqualFunctioncustomHashFunction 的 C 风格原型在 此处此处

[mySet member:valueToCheck] should not be crashing. NSValue's isEqual: works fine when I try it here, and in fact probably calls isEqualToValue: when given another NSValue to compare to. Is valueToCheck really an NSValue, or is it a CGPoint?

There is no way to override the default hash and comparison methods for NSSet. But NSSet is toll-free bridged with CFSetRef, and you can easily specify custom hashing and comparison methods there:

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

The constraints on these functions are presumably the same as on NSObject's hash and isEqual: methods, anything that is equal must have the same hash. The C-style prototypes for customEqualFunction and customHashFunction are described here and here.

紫罗兰の梦幻 2024-11-09 07:40:59

一种解决方案是子类化 NSSet 并重写 member: 来进行自己的比较。然后,您可以简单地调用 isEqualToValue: 进行自己的比较。查看 NSSet 文档

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

One solution would be to subclass NSSet and override member: to do your own comparison. Your own comparison could then simple call isEqualToValue:. Have a look at the subclassing notes in the NSSet documentation.

Another approach would be to add a category to NSValue that implements isEqual:. In this case I'd prefer subclassing because it's a more constrained solution.

暖心男生 2024-11-09 07:40:59

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

您还需要实现 NSCopying 协议,如果您的点是不可变的(只需在 -copyWithZone: 中保留并返回 self ),该协议也很简单。

It's not just a problem with -isEqual:, you may also have an issue with the -hash method. If you want to use an NSSet, you should probably create a custom class that wraps the CGPoint. -isEqual: is then trivial and -hash could be implemented by some method of combining the bits of both coordinates and then treating them as a NSUInteger.

You'll also want to implement the NSCopying protocol which is also trivial if your points are immutable (just retain and return self in -copyWithZone:).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文