调试为啥 SKScene init(fileNamed:) 返回 nil

Posted

技术标签:

【中文标题】调试为啥 SKScene init(fileNamed:) 返回 nil【英文标题】:Debug why SKScene init(fileNamed:) returns nil调试为什么 SKScene init(fileNamed:) 返回 nil 【发布时间】:2016-03-31 11:10:15 【问题描述】:

TLTR:

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

原因:.sks 文件在第二次初始化调用时不存在。该问题与ODR 实现和/或行为有关。

描述:

使用SpriteKit 构建的游戏。我的SKScene 子类的init(fileNamed:)返回nil。我试图理解“为什么?”如何?”调试此问题。

我的初始化SKScene子类的代码:

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

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

let scene = sceneType.init(fileNamed: fileName)

注意事项:

    此代码在运行时的某个时间点起作用,但在其他时间点不起作用。 当通过Xcode构建目标时,转到Products -> AppName.app,右键单击“Show in Finder”,没有Level1.sks。也许没关系,因为应用程序使用了ODR,而Level1.sks 标记有“Level1”标签,即使它在初始安装标签中 当断点设置为let sceneType:... 行时,我可以通过相应的子类和文件名轻松创建其他游戏场景,但expression TBTLevelScene(fileName:"Level1") 返回nil。 我尝试检查主包中是否有 Level1.sks,但对于所有场景,下面的代码总是显示“文件不可用”,因此该方法似乎是错误的。 游戏的场景加载架构由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 标签。标签位于 Initial Install Tags 预取组中。

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

【问题讨论】:

【参考方案1】:

这里发生了一些事情,但最终发生的事情是,听起来您的“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 文件复制到您构建的应用中。

打开目标的“构建阶段”部分和click on the "Copy Bundle Resources" area。确保您的 .sks 文件包含在其中。

【讨论】:

检查文件存在的方法确实有效。它显示“Level1.sks”在应用程序崩溃时可用。但是,“复制捆绑资源”区域确实有“Level1.sks”。 文件没有复制到构建的应用程序中一定有某种原因。构建日志有什么有用的吗? (使用“显示所有消息”) 请看我的更新。您的代码被剪断有助于缩小案件范围。谢谢。 @Michael Dautermann 我将您的答案标记为“已接受”,因为它帮助我找出了 init 返回nil 的关键原因。问题“为什么在第二次通话期间丢失了文件?”是另一种故事,可能是完全不同的问题。感谢您的帮助!

以上是关于调试为啥 SKScene init(fileNamed:) 返回 nil的主要内容,如果未能解决你的问题,请参考以下文章

我应该在 init 方法中还是在 didMove(toView:) 中以编程方式设置 SKScene?

SKScene:移动和调整调试字段的大小

SceneKit中的SKScene

为啥 SKSpriteNode(fileNamed:) 使用 Swift 在 iOS 中生成 nil?

向 SKSpriteNode(或 SKScene)添加背景模糊

在 Sprite Kit 游戏中重置 SKScene