如何解决 Swift Playgrounds 中的“运行此页面时出现问题”消息?

Posted

技术标签:

【中文标题】如何解决 Swift Playgrounds 中的“运行此页面时出现问题”消息?【英文标题】:How do I address the “There was a problem running this page” message in Swift Playgrounds? 【发布时间】:2020-05-13 21:40:41 【问题描述】:

我正在尝试使用 SceneKit 为 WWDC 学生挑战赛制作一些东西,这要求我的项目位于 Swift 操场上。我不断收到“运行此页面时出现问题”的消息。它不提供错误消息。它只是建议检查我的代码或重新开始。我曾尝试单独删除代码片段,但找不到此问题的根源。我还尝试在 man Xcode playground 中运行它,它提供了警告,我引用了“操场无法继续运行,因为操场源代码已经运行”。我被困住了。我的代码有什么问题。

import UIKit
import SceneKit
import QuartzCore 
import PlaygroundSupport

class GameScene: UIViewController, SCNSceneRendererDelegate 
    var primaryView: SCNView!
    var primaryScene: SCNScene!
    var cameraNode: SCNNode!
    
    override func viewDidLoad() 
        sceneAndViewInit()
        cameraInit()
        createGround()
        moonInit()
    
    
    func createGround() 
        var ground = SCNBox(width: 200, height: 1, length: 200, chamferRadius: 0)
        var groundPhysicsShape = SCNPhysicsShape(geometry: ground, options: nil) 
        var groundNode = SCNNode(geometry: ground)
        ground.firstMaterial?.diffuse.contents = UIColor.orange
        ground.firstMaterial?.specular.contents = UIColor.white
        groundNode.position = SCNVector3(0, -6, 0)
        groundNode.physicsBody = SCNPhysicsBody(type: .static, shape: groundPhysicsShape)
        primaryScene.rootNode.addChildNode(groundNode)
    
    
    func sceneAndViewInit() 
        primaryView = SCNView(frame: CGRect(x: 0, y: 0, width: 500, height: 300))
        primaryView.allowsCameraControl = true
        primaryView.autoenablesDefaultLighting = true
        
        primaryScene = SCNScene()
        
        primaryView.scene = primaryScene
        primaryView.isPlaying = true
    
    
    func cameraInit() 
        var cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 2)
        cameraNode.camera?.fieldOfView = 65
        cameraNode.camera?.wantsHDR = false
        primaryScene.rootNode.addChildNode(cameraNode)
    
    
    func moonInit() 
        let moonScene = SCNScene(named: "Moon.scn")
        var moonNode = moonScene?.rootNode.childNode(withName: "Sphere", recursively: true)
        var moonPhysicsShape = SCNPhysicsShape(node: moonNode!, options: nil)
        moonNode?.position = SCNVector3(0, 0, 0)
        moonNode?.scale = SCNVector3(1, 1, 1)
        moonNode?.name = "Moon"
        moonNode?.physicsBody = SCNPhysicsBody(type: .static, shape: moonPhysicsShape)
        primaryScene.rootNode.addChildNode(moonNode!)
    
    
    func renderer(_ aRenderer: SCNSceneRenderer, updateAtTime time: TimeInterval) 
        print(time)
    


let gameScene = GameScene()
PlaygroundPage.current.liveView = gameScene

(“Moon.scn”是我在资源/文件部分中的一个文件及其纹理,但没有任何与月球相关的代码我仍然遇到问题。)

【问题讨论】:

您找到解决方案了吗?遇到同样的问题。 我添加了一个答案,解释了为我解决了什么问题以及我对这个问题的了解。 【参考方案1】:

要查看完整的错误消息,请转到设置应用 -> 游乐场 -> 开启创作调试模式。这并不能直接解决问题,但对定位错误更有帮助。

【讨论】:

非常感谢! 创作调试模式是否也显示(或者有办法让它显示)代码上的完整错误或加载 Playgrounds 的错误?我能找到的唯一resource 谈论创作调试模式是在为分发创建游乐场的背景下这样做的,但它绝不是全面的。如果创作调试模式也适用于代码本身,那就太棒了。 我认为创作调试模式只会显示编译错误,虽然我自己没有尝试过。 link 显示错误编译源的详细错误消息,但不显示运行时错误,如果这是您所要求的。 明白。谢谢你的澄清。这非常有用。【参考方案2】:

我找到了解决此问题的方法。但是,我只能为您提供一个关于问题是什么以及如何解决它的大致想法。 问题似乎出在类顶部的变量声明上。

var primaryView: SCNView!
var primaryScene: SCNScene!
var cameraNode: SCNNode!

类型后面的感叹号表示该变量是implicitly-unwrapped optional(我引用this Stack Overflow response,它更深入地解释了这是什么),但或多或​​少,该变量将自动强制展开用来。我对 Swift 的了解多于技术知识,所以我的猜测是,当创建 GameScene 对象时,合成初始化程序会尝试设置这些变量,出于某种原因,它需要从变量中读取,获取nil,无法继续。

解决方案似乎是将变量的值放在它们的初始声明中(可能有更好的解决方案,但这至少在我的测试中有效。),因此它们不是 nil 的初始化程序。现在我不能在这里完全解释这个问题的原因是这似乎只对SCNScene 变量是必要的。我真的不知道为什么会这样。

代码(***标记重要的cmets):

import UIKit
import SceneKit
import QuartzCore 
import PlaygroundSupport

class GameScene: UIViewController, SCNSceneRendererDelegate 
    var primaryView: SCNView!// = SCNView(frame: CGRect(x: 0, y: 0, width: 500, height: 300)) //***This seems to work for reasons beyond me with the implicitly-unwrapped optional***
    var primaryScene = SCNScene() //***The implicitly unwrapped optional is removed here***
    var cameraNode = SCNNode() //***The implicitly unwrapped optional is removed here (I am not sure if that is necessary but it probably good practice not to use it anywhere intros code.  I use it earlier to demonstrate its weird complexities.)***
    
    override func viewDidLoad() 
        sceneAndViewInit()
        cameraInit()
        createGround()
        //moonInit() ***I removed this for simplicity in the answer***
    
    
    func createGround() 
        var ground = SCNBox(width: 200, height: 1, length: 200, chamferRadius: 0)
        var groundPhysicsShape = SCNPhysicsShape(geometry: ground, options: nil) 
        var groundNode = SCNNode(geometry: ground)
        ground.firstMaterial?.diffuse.contents = UIColor.orange
        ground.firstMaterial?.specular.contents = UIColor.white
        groundNode.position = SCNVector3(0, -6, 0)
        groundNode.physicsBody = SCNPhysicsBody(type: .static, shape: groundPhysicsShape)
        primaryScene.rootNode.addChildNode(groundNode)
    
    
    func sceneAndViewInit() 
        primaryView = SCNView(frame: CGRect(x: 0, y: 0, width: 500, height: 300))
        primaryView.allowsCameraControl = true
        primaryView.autoenablesDefaultLighting = true
        
        //primaryScene = SCNScene() ***This is not necessary when it is declared above***
        
        self.primaryView.scene = primaryScene
        //primaryView.isPlaying = true
        
        self.view = primaryView //***I realized later you need this bit of code or the program will only display a blank screen***
    
    
    func cameraInit() 
        //var cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 2)
        cameraNode.camera?.fieldOfView = 65
        cameraNode.camera?.wantsHDR = false
        primaryScene.rootNode.addChildNode(cameraNode)
    
    
    func moonInit() 
        let moonScene = SCNScene(named: "Moon.scn")
        var moonNode = moonScene?.rootNode.childNode(withName: "Sphere", recursively: true)
        var moonPhysicsShape = SCNPhysicsShape(node: moonNode!, options: nil)
        moonNode?.position = SCNVector3(0, 0, 0)
        moonNode?.scale = SCNVector3(1, 1, 1)
        moonNode?.name = "Moon"
        moonNode?.physicsBody = SCNPhysicsBody(type: .static, shape: moonPhysicsShape)
        primaryScene.rootNode.addChildNode(moonNode!)
    
    
    func renderer(_ aRenderer: SCNSceneRenderer, updateAtTime time: TimeInterval) 
        print(time)
    


let gameScene = GameScene()
PlaygroundPage.current.liveView = gameScene

最后一点: self.view = primaryView 代码非常重要。我在完整的代码中做了一个注释,但我发现这种方式太难在互联网上找到了。我认为这与UIViewController 有关(我对UIKit 了解不多。),但如果您现在有那段代码,SceneKitUIKit 只会显示一个空白屏幕。如果您没有弄清楚这些是单独的问题,那么它们真的很难破译。

【讨论】:

以上是关于如何解决 Swift Playgrounds 中的“运行此页面时出现问题”消息?的主要内容,如果未能解决你的问题,请参考以下文章

如何将视频保存到 Swift Playgrounds 中的 URL

如何将数据从 Playground 页面传递到 Swift Playgrounds 中的另一个 Playground 页面?

您如何在 Swift Playgrounds 中的 iPad 上的 SwiftUI 中渲染 Text("Content") 与 Mac 上的 Xcode?

如何在 Swift Playgrounds 中使用带有纹理的 SKNode 设置 SKScene?

如何在 XCode 8 Playgrounds 中使用 Swift 2.3?

Swift Playgrounds 中的 JavaScriptCore