使用场景工具包和快速IOS调用func时出现致命错误

时间:2016-03-01 19:23:41

标签: ios swift scenekit

我有一点问题,下载后我想启动一个功能,但我有这个致命的错误:

  

致命错误:在解包可选值时意外发现nil

当我的下载结束时,我称之为功能telechargementOK()

func telechargementOK() {
    println("Telechargement ok")
    renduScene()
}

func renduScene() {
    println("Chargement de la vue 3D")

    let scnView2 = self.view3D as SCNView
    scnView2.scene = SCNScene(named: "art.scnassets/MASTER.dae")
    scnView2.autoenablesDefaultLighting = true
    scnView2.allowsCameraControl = true


    let filemgr = NSFileManager.defaultManager()
    var documentsDirectoryURL = filemgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false, error: nil)
    documentsDirectoryURL = documentsDirectoryURL?.URLByAppendingPathComponent("/Modules.scnassets/Module-01.dae")
    let module1Scene = SCNScene(URL: documentsDirectoryURL!, options: nil, error: nil)
    //println("\(module1Scene)")
    scnViewModule1.scene = module1Scene
    module1 = scnViewModule1.scene?.rootNode.childNodeWithName("Module-01", recursively: true)
    //println("\(module1)")
    scnView2.scene?.rootNode.addChildNode(module1!)

    tapRecognizer.numberOfTapsRequired = 1
    tapRecognizer.numberOfTouchesRequired = 1
    tapRecognizer.addTarget(self, action: "sceneTapped:")
    scnView2.addGestureRecognizer(tapRecognizer)
}

当我将此代码用于viewDidLoad()时,一切正常......

Stoun

更新:

这是我的完整代码:

//
//  ViewController.swift
//  Gare et Connexions
//
//  Created by Stoun on 25/02/2016.
//  Copyright (c) 2016 Stoun. All rights reserved.
//

import UIKit
import SceneKit
import Foundation

class ViewController: UIViewController {

@IBOutlet weak var view3D : UIView?

let tapRecognizer = UITapGestureRecognizer()

var scnView3 = SCNView()
var scnViewModule1 = SCNView()
var module1 = SCNNode?()

var connexion = NSString()


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    //1 - on va regarder pour copier les modules dans un dossier du dossier documents de l'appli
    let filemgr = NSFileManager.defaultManager()
    var error : NSError?
    let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
    //test dossier
    // path to documents directory
    let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String
    // create the custom folder path
    let myCustomDataDirectoryPath = documentDirectoryPath.stringByAppendingPathComponent("/Modules.scnassets")
    // check if directory does not exist
    if NSFileManager.defaultManager().fileExistsAtPath(myCustomDataDirectoryPath) == false {

        // create the directory
        var createDirectoryError: NSError? = nil
        NSFileManager.defaultManager().createDirectoryAtPath(myCustomDataDirectoryPath, withIntermediateDirectories: false, attributes: nil, error: &createDirectoryError)

        // handle the error, you may call an exception
        if createDirectoryError != nil {
            println("Handle directory creation error...")
        }

    }


    //2-on teste la connexion
    let status = Reach.connectionStatus()
    switch status {
    case .Unknown, .Offline:
        println("Not connected")
        connexion = "NON"
    case .Online(.WWAN):
        println("Connected via WWAN")
        connexion = "3G"
    case .Online(.WiFi):
        println("Connected via WiFi")
        connexion = "WIFI"
    }

    //3 - on télécharge ou pas
    if ((connexion == "NON") || (connexion == "3G")){
        //on telecharge pas, on mets une alerte pour dire que les modules ne sont peut-être pas à jour
        // create the alert
        let alert = UIAlertController(title: "MESSAGE IMPORTANT", message: "Vous n'êtes pas connecté à internet ou vous avez une connexion en 3G. Les modules ne sont peut-être pas à jour. Merci de vous connecter via un réseau wifi pour mettre à jour les modules.", preferredStyle: UIAlertControllerStyle.Alert)
        // add an action (button)
        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
        // show the alert
        dispatch_async(dispatch_get_main_queue(), {
            self.presentViewController(alert, animated: true, completion: nil)
        })
        renduScene()
    }
    else if (connexion == "WIFI"){
        //on télécharge
        var URL = NSURL(string: "http://urbis-guadeloupe.fr/stoun/3Dgare/Module-01-opt.dae.zip")
        //var URL = NSURL(string: "http://urbis-guadeloupe.fr/stoun/3Dgare/B00001.png")
        Downloader.load(URL!)
        //renduScene()

        scnView3 = self.view3D as SCNView

        //on vois pour la suite - afficher la 3D
        //let scnView = self.view3D as SCNView
        scnView3.scene = SCNScene(named: "art.scnassets/MASTER.dae")
        scnView3.autoenablesDefaultLighting = true
        scnView3.allowsCameraControl = true

        //scnViewModule1 = self.view3D as SCNView
        //test chargement dossier document
        /*if ((connexion == "NON") || (connexion == "3G")){
        var documentsDirectoryURL = filemgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false, error: nil)
        documentsDirectoryURL = documentsDirectoryURL?.URLByAppendingPathComponent("/Modules.scnassets/Module-01-opt.dae")
        let module1Scene = SCNScene(URL: documentsDirectoryURL!, options: nil, error: nil)
        //println("\(module1Scene)")
        scnViewModule1.scene = module1Scene
        module1 = scnViewModule1.scene?.rootNode.childNodeWithName("Module-01", recursively: true)
        //println("\(module1)")
        scnView3.scene?.rootNode.addChildNode(module1!)
        /*let module1Scene = SCNScene(named: "art.scnassets/Module-01.dae")
        scnViewModule1.scene = module1Scene
        module1 = scnViewModule1.scene?.rootNode.childNodeWithName("Module-01", recursively: true)
        scnView.scene?.rootNode.addChildNode(module1!)*/
        }*/
        tapRecognizer.numberOfTapsRequired = 1
        tapRecognizer.numberOfTouchesRequired = 1
        tapRecognizer.addTarget(self, action: "sceneTapped:")
        scnView3.addGestureRecognizer(tapRecognizer)
    }

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func sceneTapped(recognizer: UITapGestureRecognizer) {

    let scnView = self.view3D as SCNView

    let location = recognizer.locationInView(scnView)

    let hitResults = scnView.hitTest(location, options: nil)
    if hitResults?.count > 0 {
        let result = hitResults![0] as SCNHitTestResult
        let node = result.node
        println("Node select : \(result.node.name)")
        if (result.node.name == "Module-01"){
            println("Module-01")
        }
    }
}

func telechargementOK(){

    println("Telechargement ok")
    renduScene()

}

func renduScene() {
    println("Chargement de la vue 3D")

    if let scnView2 = self.view3D as? SCNView{
        println(1)

    scnView2.scene = SCNScene(named: "art.scnassets/MASTER.dae")
    scnView2.autoenablesDefaultLighting = true
    scnView2.allowsCameraControl = true

    let filemgr = NSFileManager.defaultManager()
    var documentsDirectoryURL = filemgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false, error: nil)
    documentsDirectoryURL = documentsDirectoryURL?.URLByAppendingPathComponent("/Modules.scnassets/Module-01-opt.dae")
    let module1Scene = SCNScene(URL: documentsDirectoryURL!, options: nil, error: nil)
    println("\(module1Scene)")
    scnViewModule1.scene = module1Scene
    module1 = scnViewModule1.scene?.rootNode.childNodeWithName("Module-01", recursively: true)
    println("\(module1)")
    scnView2.scene?.rootNode.addChildNode(module1!)

    tapRecognizer.numberOfTapsRequired = 1
    tapRecognizer.numberOfTouchesRequired = 1
    tapRecognizer.addTarget(self, action: "sceneTapped:")
    scnView2.addGestureRecognizer(tapRecognizer)
    }
    else {
        println(2)
        let filemgr = NSFileManager.defaultManager()
        var documentsDirectoryURL = filemgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false, error: nil)
        documentsDirectoryURL = documentsDirectoryURL?.URLByAppendingPathComponent("/Modules.scnassets/Module-01-opt.dae")
        let module1Scene = SCNScene(URL: documentsDirectoryURL!, options: nil, error: nil)
        println("\(module1Scene)")
        scnViewModule1.scene = module1Scene
        module1 = scnViewModule1.scene?.rootNode.childNodeWithName("Module-01", recursively: true)
        println("\(module1)")
        scnView3.scene?.rootNode.addChildNode(module1!)

    }
}

}

当设备连接到互联网时,这是日志:

Connected via WiFi
Success: 200
Copy from serveur successful
Remove ZIP successful
Remove dae from folder successful
Copy dae in folder successful
Remove dae from folder successful
Telechargement ok
Chargement de la vue 3D
2
Optional(<SCNScene: 0x1780e1c80>)
Optional(<SCNNode: 0x100b11a20 'Module-01' | 4 children>)

但SCNNode Module-01不在视图

当设备离线时,日志:

Not connected
Chargement de la vue 3D
1
Optional(<SCNScene: 0x1780f7c80>)
Optional(<SCNNode: 0x13fe271b0 'Module-01' | 4 children>)

一切都在观点上 我不明白为什么当设备在线时,节点不在视图上!

Stoun

2 个答案:

答案 0 :(得分:0)

你使用module1!而不检查module1是不是nil:你应该检查它。

答案 1 :(得分:0)

您正在从SCNView和其他顶级对象(scnViewModule1scnView2)开始查找子节点,这些对象在viewDidLoad()之前不存在。因此,您的搜索返回nil,并且您的力展开失败。如果从viewDidLoad()调用方法,则场景已经实例化,因此您的调用成功。

您无需通过视图来操纵场景。相反,尝试

scnViewModule1.scene = module1Scene
if let module1 = module1Scene.rootNode.childNodeWithName("Module-01", recursively: true) {
    module1Scene.rootNode.addChildNode(module1)
}