SpriteKit。从可选到强制解包的更改会导致应用程序崩溃

时间:2017-01-03 20:04:41

标签: sprite-kit swift3

我正在关注SpriteKit的教程,该教程存在IF语句问题。该线的逻辑如下:如果子弹和小行星发生碰撞,则将其移除。

if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid {
   // remove bullet and asteroid
}

当试图确保小行星(body2.node)在可关闭区域之前可以关闭之前,会出现问题。为此,作者添加了以下内容:

body2.node?.position.y < self.size.height

制作完整的IF语句如下:

if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid && body2.node?.position.y < self.size.height {
   // remove bullet and asteroid
}

显然这条线适用于Swift 2但是Swift 3进行了修正,从一个可选的位置改变了位置,并且强行打开了位置。

    if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid && body2.node!.position.y < self.size.height {
        // remove bullet and asteroid        
    }

通过强行展开位置,当三个物体碰撞时,应用程序崩溃了“我认为”。在看屏幕时真的很难说。

我正在测试下面的代码,我还没有遇到任何问题。你们认为下面的修复工作会起作用吗?我想的是,如果我确定body2.node不是nil,那么应用程序就没有理由崩溃,因为在尝试强行打开它时不会遇到nil。

if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid {
    // If the bullet has hit the asteroid
  if body2.node != nil {
    if ( body2.node!.position.y < self.size.height ) {
       // remove bullet and asteroid
    }           
  }           
}

否则,如果有其他方式,你们可以建议一种不同的方式来编写原始的IF声明吗?

由于

2 个答案:

答案 0 :(得分:5)

是的,if != nil语句(目前正在编写)将防止强制解包引起的崩溃。

另一种方法是在Swift中使用if let语法:

if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid {
    // If the bullet has hit the asteroid
    if let body2Node = body2.node {
        if body2Node.position.y < self.size.height {
           // remove bullet and asteroid
        }           
    }           
}

好处是它会从代码中删除!,并且更清楚地将nil检查与您稍后使用的变量相关联。

答案 1 :(得分:4)

nathan有正确的答案,但更好的选择是使用guard代替保护你的功能:

...

guard let  body1Node = body1.node, let  body2Node = body2.node else {return}
//Beyond this point we need to guarentee both nodes exist

if body1.categoryBitMask == PhysicsCategories.bullet && body2.categoryBitMask == PhysicsCategories.asteroid {
    // If the bullet has hit the asteroid
    if body2Node.position.y < self.size.height {
       // remove bullet and asteroid
    }           

}

通过使用保护,我们减少了嵌套,并且我们知道超出这一点,物理主体必须包含一个节点,除非我们在函数结束之前删除它,这将消除进一步检查节点是否存在的需要。

作为旁注,我总是建议在更新阶段结束时删除节点以避免这样的问题,而只是标记节点,以便您将不再使用它。