如何在SpriteKit中使用Swift的"enumerateChildNodesWithName"方法?

17

我正在使用Swift和SpriteKit制作游戏。

在Objective-C中,我可以使用以下方法:

 (void)enumerateChildNodesWithName:(NSString *)name usingBlock:(void (^)(SKNode *node, BOOL *stop))block

我希望对那个*node执行一些操作,但是我无法在Swift中让这个函数正常工作。基本上,我不知道如何在Swift中引用那个节点。

这是我正在使用的代码,但我在“usingBlock:”部分遇到了问题。我尝试了很多方法很多小时,但没有成功。请帮忙!

func spawnEnemy() -> () {
  let enemy = SKSpriteNode(imageNamed: "enemy")
  enemy.name = "enemy"
  enemy.position = CGPointMake(100, 100)
  self.addChild(enemy)
}

func checkCollisions() -> () {
  self.enumerateChildNodesWithName("enemy", usingBlock: ((SKNode!, CMutablePointer<ObjCBool>) -> Void)?)
}
1个回答

45

现在不要指望自动完成会插入你所需的代码 - 它会从“头文件”中插入签名,但块签名与当您为块参数插入自己的闭包时所需的声明不同。

编写闭包的正式方法是在大括号内复制签名,添加本地参数名称,并使用in关键字标记闭包体的开始:

self.enumerateChildNodesWithName("enemy", usingBlock: {
    (node: SKNode!, stop: UnsafeMutablePointer <ObjCBool>) -> Void in 
    // do something with node or stop
})

但 Swift 的类型推断意味着你不必写那么多。相反,你只需要命名参数,因为它们的类型(以及闭包的返回类型)是已知的:

self.enumerateChildNodesWithName("enemy", usingBlock: {
    node, stop in 
    // do something with node or stop
})

你还可以使用尾随闭包语法:

self.enumerateChildNodesWithName("enemy") {
    node, stop in 
    // do something with node or stop
}
你甚至可以通过位置引用参数,删除本地参数名称,例如使用$0代替node,但这样做会使你的代码难以阅读。最好将$0和其他类似的内容保留给闭包,其中很明显知道参数是什么,例如与mapsort一起使用的闭包。
请参阅The Swift Programming Language中的Closures以获取更多解释。
此外,因为stop是一个UnsafeMutablePointer,所以使用它的语法与ObjC略有不同:设置stop.memory = true以跳出枚举。

2
使用 stop.memory = true 给我报错了,所以我使用了 stop.withUnsafePointer { $0.memory = true },正如这里所推荐的。 - rv123
好的发现。已编辑答案。 - rickster
但是当针对iOS 7(Xcode 6 b7)时似乎无法正常工作。有人实现过吗? - Johan
1
@Gatada:据我所知,导入的API中的ObjC BOOL *类型在beta 5中再次更改了。因此,我们回到了只设置stop.memory的方式。已更新答案。 - rickster
我不确定自从6月份的Swift Beta 1以来,BOOL *参数已经改变了多少次其导入的Swift类型。无论如何,这是在闭包语法中使用类型推断的一个很好的理由 - 如果你只写node, stop in,你就不必在新的Xcode版本中更改声明。 - rickster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接