gpt4 book ai didi

ios8 - 为什么 [NSSet containsObject] 在 iOS8 中对 SKNode 成员失败?

转载 作者:行者123 更新时间:2023-12-01 12:39:42 24 4
gpt4 key购买 nike

NSSet 添加了两个对象,但是当我检查成员资格时,我找不到其中之一。

下面的测试代码在 iOS7 中运行良好,但在 iOS8 中失败。

SKNode *changingNode = [SKNode node];
SKNode *unchangingNode = [SKNode node];
NSSet *nodes = [NSSet setWithObjects:unchangingNode, changingNode, nil];

changingNode.position = CGPointMake(1.0f, 1.0f);

if ([nodes containsObject:changingNode]) {
printf("found node\n");
} else {
printf("could not find node\n");
}

输出:

could not find node

iOS7 和 iOS8 之间发生了什么,我该如何解决?

最佳答案

SKNodeisEqualhash 的实现在 iOS8 中已经改变,包括对象的数据成员(而不仅仅是内存地址对象)。

Apple documentation for collections警告这种确切情况:

If mutable objects are stored in a set, either the hash method of the objects shouldn’t depend on the internal state of the mutable objects or the mutable objects shouldn’t be modified while they’re in the set. For example, a mutable dictionary can be put in a set, but you must not change it while it is in there.

而且,更直接地说,here :

Storing mutable objects in collection objects can cause problems. Certain collections can become invalid or even corrupt if objects they contain mutate because, by mutating, these objects can affect the way they are placed in the collection.

一般情况描述in other questions in detail .但是,我将重复对 SKNode 示例的解释,希望它能帮助那些在升级到 iOS8 时发现此问题的人。

在示例中,SKNode 对象 changingNode 被插入到 NSSet 中(使用哈希表实现)。计算对象的哈希值,并在哈希表中为它分配一个桶:假设桶 1。

SKNode *changingNode = [SKNode node];
SKNode *unchangingNode = [SKNode node];
printf("pointer %lx hash %lu\n", (uintptr_t)changingNode, (unsigned long)changingNode.hash);
NSSet *nodes = [NSSet setWithObjects:unchangingNode, changingNode, nil];

输出:

pointer 790756a0 hash 838599421

然后修改changingNode。修改会导致对象的散列值发生变化。 (在 iOS7 中,像这样更改对象不会更改其哈希值。)

changingNode.position = CGPointMake(1.0f, 1.0f);
printf("pointer %lx hash %lu\n", (uintptr_t)changingNode, (unsigned long)changingNode.hash);

输出:

pointer 790756a0 hash 3025143289

现在,当 containsObject 被调用时,计算出的哈希值(可能)被分配给不同的桶:比如桶 2。桶 2 中的所有对象都使用 isEqual 与测试对象进行比较,但当然都返回 NO。

在一个真实的例子中,对 changedObject 的修改可能发生在别处。如果您尝试在 containsObject 调用的位置进行调试,您可能会困惑地发现该集合包含一个与查找对象具有完全相同地址和哈希值的对象,但查找失败.

替代实现(每个都有自己的一组问题)

  • 仅在集合中使用不变的对象。

  • 只有在您拥有完全控制权时才将对象放入集合中,现在并永远关注他们对 isEqualhash 的实现。

  • 跟踪一组(非保留)指针而不是一组对象:[NSSet setWithObject:[NSValue valueWithPointer:(void *)changingNode]]

    /li>
  • 使用不同的集合。例如,NSArray 将受到以下更改的影响isEqual 但不会受到 hash 更改的影响。 (当然,如果您尝试对数组进行排序以便更快地查找,您将拥有类似的问题。)

  • 对于我的真实情况,通常这是最好的选择:使用 NSDictionary,其中键是 [NSValue valueWithPointer],对象是保留的指针。这给了我:快速查找一个对象,即使对象发生变化也是有效的;快速删除;并保留收藏中的元素。

  • 与上一个类似,具有不同的语义和一些其他有用的选项:使用带有选项 NSMapTableObjectPointerPersonalityNSMapTable 以便将关键对象视为散列指针和平等。

关于ios8 - 为什么 [NSSet containsObject] 在 iOS8 中对 SKNode 成员失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26143970/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com