调试为什么 SKScene init(fileNamed:) returns nil

Debug why SKScene init(fileNamed:) returns nil

TLTR:

问题: SKScene 子类的 init(fileNamed:)returns nil

原因:第二次初始化调用时.sks文件不存在。这个问题在某种程度上与 ODR 实施 AND/OR 行为有关。

描述:

使用 SpriteKit 构建的游戏。我的 SKScene 子类的 init(fileNamed:)returns nil。我试图理解 "why?" 和 "how?" 来调试这个问题。

我初始化 SKScene 子类的代码:

/// the hierarchy: SKScene -> TBTBaseScene -> TBTLevelScene

let sceneType: TBTBaseScene.Type = TBTLevelScene.self
let fileName = "Level1"

let scene = sceneType.init(fileNamed: fileName)

注意事项:

  1. 此代码在运行时的某个时间点有效,但在另一个时间点无效。
  2. 通过 Xcode 构建目标时,转到产品 -> AppName.app,右键单击,"Show in Finder",没有 Level1.sks。也许没关系,因为应用程序使用 ODR 并且 Level1.sks 标记有 "Level1" 标签,即使它在 Initial Install Tags
  3. 当断点设置到 let sceneType:... 行时,我可以通过各自的子类和文件名轻松创建其他游戏场景,但是 expression TBTLevelScene(fileName:"Level1") returns nil.
  4. 我试图检查主包中是否有 Level1.sks,但下面的代码对于所有场景总是显示 "FILE NOT AVAILABLE",所以该方法似乎是错误的。
  5. 游戏的场景加载架构由 DemoBots Sample Code 驱动。您可以在 LoadSceneOperation.swift 中看到类似的方法。不过,那里的初始化在所有情况下都可以正常工作。

我用来检查 "Level1" 或 "Level1.sks" 是否存在的代码,基于 this answer:

let path = NSBundle.mainBundle().bundlePath
let url = NSURL(fileURLWithPath: path)
let filePath = url.URLByAppendingPathComponent(fileName).absoluteString
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(filePath) {
    print("FILE AVAILABLE")
} else {
    print("FILE NOT AVAILABLE")
}

更新:

Michael Dautermann 提供的检查文件的方法确实有效,它证明了原因:Level1.sks 在第二次尝试加载它时 存在。

项目中的Level1.sks文件被添加到"Copy Bundle Resources"区域并具有"Level1" ODR标签。该标签位于 初始安装标签 预取组中。

ORD 实现中肯定存在一些错误,该错误会在不需要时处理资源 (Level1.sks),并且在需要时不会再次加载它。我会继续努力弄清楚。 (似乎,到目前为止,SO 社区与此无关)

这里发生了一些事情,但最终发生的事情是听起来您的“Level1”文件没有在构建的应用程序中结束。

1)

你的文件存在检查代码混合文件 URL 和文件路径太多了。将您的代码更改为如下所示:

// if nodePath is nil, then it's not found in the bundle
if let nodePath = NSBundle.mainBundle().pathForResource("Level1", ofType: "sks")
{
    print("FILE AVAILABLE")
} else {
    print("FILE NOT AVAILABLE")
}

2)

确保您的 .sks 文件被复制到您构建的应用程序中。

打开目标的 "Build Phases" 部分和 click on the "Copy Bundle Resources" area。确保您的 .sks 文件包含在其中。