Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
367 views
in Technique[技术] by (71.8m points)

objective c blocks - How to use "enumerateChildNodesWithName" with Swift in SpriteKit?

I'm using Swift to make a game in SpriteKit.

In Objective-C I could use the following method:

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

to perform actions on that *node, but I can't get this function working in Swift. Basically, I don't know how to reference that node in Swift.

This is the code I'm using, but I'm having trouble with the "usingBlock:" part. I've tried many things for many hours, but have not succeeded. Help please!

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)?)
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For now, don't trust autocomplete to insert the code you need — it drops in signatures from the "header", but a block signature is not the same as the declaration you need when inserting your own closure for a block parameter.

The formal way to write a closure would be to replicate the signature inside braces, adding local parameter names and using the in keyword to mark the start of the closure body:

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

But Swift's type inference means you don't have to write that much. Instead, you can just name the parameters, because their type (as well as the closure's return type) is known:

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

You can also use trailing closure syntax:

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

(You can even drop the local parameter names and refer to parameters by position — e.g. $0 for node — but here isn't a great place to do that because it makes your code far less readable. It's best to reserve $0 and friends for closures where it's blindingly obvious what the parameters are, like the closures you use with map and sort.)

See Closures in The Swift Programming Language for further explanation.


Also, because stop is an UnsafeMutablePointer, the syntax for using it is a bit different than in ObjC: set stop.memory = true to break out of enumeration.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...