2

Why does the Sprite Kit Game template project created by Xcode use as!:

if let sceneNode = scene.rootNode as! GameScene? {...}

Wouldn't the following be equally good?

if let sceneNode = scene.rootNode as? GameScene {...}

Note, this isn't the standard "what is the difference between as? and as!" question. And Downcasting optionals in Swift: as? Type, or as! Type? is very close, but isn't quite the same thing, either. The question is that the two above patterns seems functionally similar (they both downcast and unwrap), but it's unclear why the author used if let ... as! GameScene? { ... } instead of the more common and more natural if let ... as? GameScene { ... }.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
Stephenye
  • 806
  • 6
  • 12
  • thanks Rob. But in this case it does have an `if`, and it's `Bar?` (not `Bar`). When I look at the duplicate question, the answer is also saying `as!` should be only used when you know the downcast will not fail (that makes sense of course). So my understanding here is, `as! Type?` isn't adding more benefits compared to `as? Type` practically speaking (the `as! Type?` can be replaced with `as? Type` in that if statement, and is probably safer) – Stephenye Feb 11 '18 at 15:00
  • Could it just be a mistake? I suspect that the compiler will make this illegal eventually. Looks to me like the template was translated from Objective-C to Swift by someone who didn't quite know what he was doing. – matt Feb 11 '18 at 18:03

2 Answers2

2

These two patterns are very close, but are not technically the same:

  • The if let ... as! GameScene? {...} does the forced cast to GameScene? and the if let then safely unwraps the resulting optional.

  • The if let ... as? GameScene { ... } will gracefully downcast and unwrap the result.

Functionally these two are almost equivalent. The question is why the template would use the former syntax. One could argue that the as? pattern is little ambiguous because glancing at the code you cannot tell whether you're merely testing the success of a downcast or whether you're dealing with an optional, too. The template's code makes this more explicit.

All of that having been said, I would use if let ... as? GameScene { ... } pattern. It is customary.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thanks @Rob. I took another look at the code for `rootNode`, and it's of type `GKSceneRootNodeType`, and the doc says "The GKSceneRootNodeType protocol is an indirect type for game scene classes that the GKScene class can load. SKScene is the only class currently supported for loading with the GKScene class." (GameScene is a subclass of GKScene) So I guess another way to interpret this is, the template code is saying it has to be (`as!`) of type GKScene. That said, several lines after, it has this `if let view = self.view as! SKView? { ... }`, which cannot be explained this way. – Stephenye Feb 11 '18 at 19:38
  • Having said all that, I agree `if let ... as? Type {...}` is equivalent and preferable. – Stephenye Feb 11 '18 at 19:38
1

I'd say it's a mistake. In any case, the pattern if let x = y as! Type? is unnecessary and you should not imitate it. The pattern if let x = y as? Type is equivalent and usual.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thanks @matt. It might be, or perhaps the author thinks the two patterns are negligibly different. Regardless, I agree the `if let ... as? Type` pattern is equivalent and preferable. – Stephenye Feb 11 '18 at 19:44
  • Sadly, Apple's own template / sample code _often_ does not exhibit best practices. – matt Feb 11 '18 at 19:49