- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
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 之间发生了什么,我该如何解决?
最佳答案
SKNode
的 isEqual
和 hash
的实现在 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
调用的位置进行调试,您可能会困惑地发现该集合包含一个与查找对象具有完全相同地址和哈希值的对象,但查找失败.
替代实现(每个都有自己的一组问题)
仅在集合中使用不变的对象。
只有在您拥有完全控制权时才将对象放入集合中,现在并永远关注他们对 isEqual
和 hash
的实现。
跟踪一组(非保留)指针而不是一组对象:[NSSet setWithObject:[NSValue valueWithPointer:(void *)changingNode]]
使用不同的集合。例如,NSArray
将受到以下更改的影响isEqual
但不会受到 hash
更改的影响。 (当然,如果您尝试对数组进行排序以便更快地查找,您将拥有类似的问题。)
对于我的真实情况,通常这是最好的选择:使用 NSDictionary
,其中键是 [NSValue valueWithPointer]
,对象是保留的指针。这给了我:快速查找一个对象,即使对象发生变化也是有效的;快速删除;并保留收藏中的元素。
与上一个类似,具有不同的语义和一些其他有用的选项:使用带有选项 NSMapTableObjectPointerPersonality
的 NSMapTable
以便将关键对象视为散列指针和平等。
关于ios8 - 为什么 [NSSet containsObject] 在 iOS8 中对 SKNode 成员失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26143970/
我发现如果你想在 Sprite Kit 中使用物理,你必须在世界坐标中指定 anchor 。假设您有一个大节点树,这里有一辆汽车,那里有一个轮子。您只知道它们在父节点中的坐标。您想要在汽车和车轮之间定
我正在为场景创建一个 SKNode,并在每个单独的 SKNode 上记录触摸事件。我可以根据需要添加任意数量的内容,如果我触摸节点并且只有可见的节点,我才能看到日志消息,并且触摸会按预期工作。现在,如
基本上我想实现这样的目标:https://github.com/moqod/iOS-Scratch-n-See在 SpriteKit 中。 在 SKScene 中,我有一张汽车图像,2-3 种不同类型
我从一个函数返回一个 SKNode,我需要将它转换为自定义 SKNode。我收到错误消息无法将 SKNode的值分配给类型GroundNode。如果我强制转换,它会编译,但在运行时失败。我错过了什么?
我正在尝试使用 SpriteKit 模拟一只眼睛。 当用户的手指在屏幕上移动时,眼睛的瞳孔会跟踪用户的手指,但必须保持在眼睛的范围内。 我曾尝试使用 SKConstraint 解决此问题,但未成功。
我不明白为什么我在最后一行收到这个错误:'SKNode!'不是'SKNode'的子类型 func move_background(){ let enumerationBlock: (SKNod
我有一个场景,其中有许多子节点,它们是 SKNode 的子类。我正在尝试访问每个子节点的方法,但收到错误“‘SKNode’类型的值没有成员‘[成员名称]”。 全部基于 Xcode 10.2 上的 Sw
我正在使用 Sprite Kit 创建一个 iOS 应用程序,并且我正在尝试选择 (onTouchBegan) 位于另一个 SKNode 下方的 SKNode。结构是:第一层(SKNode)-第二层(
我在带有 SKScene 的 UIView 上有一个 UITapGestureRecognizer 和一个 UIPanGestureRecognizer。平移手势识别器从左到右移动一个 SKNode,
当事件发生时,SKNode 子类应该如何通知父场景? 我有一个 SKNode 子类,它根据游戏逻辑通过适本地重绘或删除节点来处理触摸事件。通知父场景(或其他同级 SKNode 实例)事件发生的 iOS
我有正确的字符串格式的 SKNODE。我想将字符串名称“A2Square”转换为名为 A2Square 的节点。 这可能吗? 是否有办法将字符串“A2Square”并以某种方式将其转换为同名的 SKN
我已经设置了场景,一切都运行良好。它看起来像这样: 但是 Controller 是在 Main.storyboard 中设置的,我想摆脱它。所以我做了这样的事情: window = UIWin
我知道为什么会出现该错误,但我无法找到解决方法。我试图让对象出现然后被删除,玩家应该在它们被删除之前尝试点击它们,但每次下一个节点即将出现时它都会崩溃。如果我在它的 func 中声明它,那么一切都会出
我的场景是,我正在沿着拱形移动现有节点,并希望它在到达另一侧时停止。一个简单的比喻是,我想让一些东西沿着彩虹移动。 虽然我当前的代码确实执行了正确的椭圆形,但它随后在我的 y 原点下方继续返回到其起点
我正在获取 int SpriteKit。并且想知道如何在 SKNode 对象上创建运动效果。 对于 UIView,我使用以下方法: +(void)registerEffectForView:(UIVi
我在不同的文件中有两个类。 在我的场景所在的“主”文件中,我调用此函数: override func touchesBegan(touches: Set, withEvent event: UIEve
好的,所以我有代码会在 1 和 2 之间选择一个随机数,并基于该数生成一个 metalCrate: 或只是一个 crate :。我想,金属 crate 应该需要轻按 2 次才能消失。不幸的是,使用我的
我目前正在同时使用 ARKit 和 CoreLocation 将元素放置在屏幕上。这些元素(例如建筑物、房屋等)基于它们自己的坐标(经度/纬度)和用户坐标放置。如您所知,即使设置了最佳精度,CoreL
我创建了一个运行良好的 SKNode 类。但是,我无法在实例化后更改其 .position。 按钮确实出现并正常工作,但在编程时不会改变位置。我已经包含了为下面的按钮制作的类,我还添加了实例化该类并调
出于学习目的,我正在使用 SpriteKit 和 Swift 5 编写一个类似 Pong 的游戏。我试图让玩家的 Racket (一个 SKNode 矩形)在 x 坐标的屏幕上移动但不能。 我试过这个
我是一名优秀的程序员,十分优秀!