user3708224
user3708224

Reputation: 1259

scenekit class issues with update to xcode 6

I know this issue is probably somewhat common with the new update and is most likely an easy fix as well, but I recently upgraded from xcode-6 beta to the full version and many of my subclasses have errors. I was using a pre-programmed scenekit 3d rotating globe which was working fine with the beta version...I am now having failed builds which is giving me the swift compiler error: 'SCNMaterial?' does not have a member named 'numerous subclasses here'

Pretty lost here so any help or direction would be greatly appreciated...thank you!

The source code from Github I am using: https://github.com/schwa/iOS-8-SceneKit-Globe-Test Additionally, below is the code from my file (same as Github files above)...

    //
    //  AppDelegate.swift
    //  SceneKitTest
    //
    //  Created by Jonathan Wight on 6/6/14.
    //  Copyright (c) 2014 schwa.io. All rights reserved.
    //

    import UIKit

    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {

        var window: UIWindow?


        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
            // Override point for customization after application launch.
            return true
        }

        func applicationWillResignActive(application: UIApplication) {
            // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
            // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
        }

        func applicationDidEnterBackground(application: UIApplication) {
            // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
            // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        }

        func applicationWillEnterForeground(application: UIApplication) {
            // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
        }

        func applicationDidBecomeActive(application: UIApplication) {
            // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        }

        func applicationWillTerminate(application: UIApplication) {
            // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        }


    }



    //
    //  GameViewController.swift
    //  SceneKitTest
    //
    //  Created by Jonathan Wight on 6/6/14.
    //  Copyright (c) 2014 schwa.io. All rights reserved.
    //

    import UIKit
    import QuartzCore
    import SceneKit

    class GameViewController: UIViewController {

        override func viewDidLoad() {
            super.viewDidLoad()

            // create a new scene
            let scene = GlobeScene()

            // create and add a light to the scene
            let lightNode = SCNNode()
            lightNode.light = SCNLight()

//error occurs with lightNode class
            lightNode.light.type = SCNLightTypeOmni
            lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
            scene.rootNode.addChildNode(lightNode)

            // create and add an ambient light to the scene
    //        let ambientLightNode = SCNNode()
    //        ambientLightNode.light = SCNLight()
    //        ambientLightNode.light.type = SCNLightTypeAmbient
    //        ambientLightNode.light.color = UIColor.darkGrayColor()
    //        scene.rootNode.addChildNode(ambientLightNode)

            // retrieve the SCNView
            let scnView = self.view as SCNView

            // set the scene to the view
            scnView.scene = scene

            // allows the user to manipulate the camera
            scnView.allowsCameraControl = true

            // show statistics such as fps and timing information
            scnView.showsStatistics = true

            // configure the view
            scnView.backgroundColor = UIColor.blackColor()

            // add a tap gesture recognizer
            let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
            let gestureRecognizers = NSMutableArray()
            gestureRecognizers.addObject(tapGesture)
            gestureRecognizers.addObjectsFromArray(scnView.gestureRecognizers!)
            scnView.gestureRecognizers = gestureRecognizers
        }

        func handleTap(gestureRecognize: UIGestureRecognizer) {
            // retrieve the SCNView
            let scnView = self.view as SCNView

            // check what nodes are tapped
            let p = gestureRecognize.locationInView(scnView)
            let hitResults = scnView.hitTest(p, options: nil)

            // check that we clicked on at least one object
//error occurs with if statement below
            if hitResults.count > 0 {
                // retrieved the first clicked object
                let result: AnyObject! = hitResults[0]

                // get its material
                let material = result.node!.geometry.firstMaterial

                // highlight it
                SCNTransaction.begin()
                SCNTransaction.setAnimationDuration(0.5)

                // on completion - unhighlight
                SCNTransaction.setCompletionBlock {
                    SCNTransaction.begin()
                    SCNTransaction.setAnimationDuration(0.5)

                    material.emission.contents = UIColor.blackColor()

                    SCNTransaction.commit()
                }

                material.emission.contents = UIColor.redColor()

                SCNTransaction.commit()
            }
        }

        override func shouldAutorotate() -> Bool {
            return true
        }

        override func supportedInterfaceOrientations() -> Int {
            if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
                return Int(UIInterfaceOrientationMask.AllButUpsideDown.toRaw())
            } else {
                return Int(UIInterfaceOrientationMask.All.toRaw())
            }
        }

        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Release any cached data, images, etc that aren't in use.
        }

    }



    //
    //  GlobeScene.swift
    //  SceneKitTest
    //
    //  Created by Jonathan Wight on 6/6/14.
    //  Copyright (c) 2014 schwa.io. All rights reserved.
    //

    import SceneKit
    import QuartzCore

    class GlobeScene: SCNScene {

        var camera: SCNCamera
        var cameraNode: SCNNode
        var ambientLightNode: SCNNode
        var globeNode: SCNNode

        override init() {

            self.camera = SCNCamera()
            self.camera.zNear = 0.01
            self.cameraNode = SCNNode()
            self.cameraNode.position = SCNVector3(x: 0.0, y: 0.0, z: 1.5)
            self.cameraNode.camera = self.camera

            self.camera.focalBlurRadius = 0;
    //        CABasicAnimation *theFocusAnimation = [CABasicAnimation animationWithKeyPath:"focalBlurRadius"];
    //        theFocusAnimation.fromValue = @(100);
    //        theFocusAnimation.toValue = @(0);
    //        theFocusAnimation.duration = 2.0;
    //        theFocusAnimation.removedOnCompletion = YES;
    //        [self.camera addAnimation:theFocusAnimation forKey:@"focus"];

            let theAmbientLight = SCNLight()
            theAmbientLight.type = SCNLightTypeAmbient
            theAmbientLight.color = UIColor(white: 0.5, alpha: 1.0)
            self.ambientLightNode = SCNNode()
            self.ambientLightNode.light = theAmbientLight

 //below theGlobeGeometry classes are where the errors occur  .diffuse, .ambient, etc.... 

            self.globeNode = SCNNode()
            let theGlobeGeometry = SCNSphere(radius: 0.5)
            theGlobeGeometry.firstMaterial.diffuse.contents = UIImage(named:"earth_diffuse.jpg")
            theGlobeGeometry.firstMaterial.ambient.contents = UIImage(named:"earth_ambient2.jpeg")
    //      theGlobeGeometry.firstMaterial.ambient.contents = UIImage(named:"earth_ambient.jpg")
            theGlobeGeometry.firstMaterial.specular.contents = UIImage(named:"earth_specular.jpg")
            theGlobeGeometry.firstMaterial.emission.contents = nil
            theGlobeGeometry.firstMaterial.transparent.contents = nil
            theGlobeGeometry.firstMaterial.reflective.contents = nil
            theGlobeGeometry.firstMaterial.multiply.contents = nil
            theGlobeGeometry.firstMaterial.normal.contents = UIImage(named:"earth_normal.jpg")

            let theGlobeModelNode = SCNNode(geometry: theGlobeGeometry)
            self.globeNode.addChildNode(theGlobeModelNode)

            let theCloudGeometry = SCNSphere(radius:0.501)
            theCloudGeometry.firstMaterial.diffuse.contents = nil
            theCloudGeometry.firstMaterial.ambient.contents = nil
            theCloudGeometry.firstMaterial.specular.contents = nil
            theCloudGeometry.firstMaterial.emission.contents = nil
            theCloudGeometry.firstMaterial.transparent.contents = UIImage(named:"earth_clouds.png")
            theCloudGeometry.firstMaterial.reflective.contents = nil
            theCloudGeometry.firstMaterial.multiply.contents = nil
            theCloudGeometry.firstMaterial.normal.contents = nil

            let theCloudModelNode = SCNNode(geometry: theCloudGeometry)
            self.globeNode.addChildNode(theCloudModelNode)

            // animate the 3d object
            let animation: CABasicAnimation = CABasicAnimation(keyPath: "rotation")
            animation.toValue = NSValue(SCNVector4: SCNVector4(x: 1, y: 1, z: 0, w: Float(M_PI)*2))
            animation.duration = 5
            animation.repeatCount = MAXFLOAT //repeat forever
            globeNode.addAnimation(animation, forKey: nil)

            super.init()

            self.rootNode.addChildNode(self.cameraNode)
            self.rootNode.addChildNode(self.ambientLightNode)
            self.rootNode.addChildNode(self.globeNode)
        }
    }

Upvotes: 0

Views: 693

Answers (1)

David Rönnqvist
David Rönnqvist

Reputation: 56635

The sample you are looking at on GitHub is old and hasn't been kept up to date as the frameworks have started to get adapted for Swift. Most of the errors you see are because the Scene Kit API has been updated to return Optionals in cases where it could return nil.

For example

lightNode.light.type = SCNLightTypeOmni

should be changed to

lightNode.light?.type = SCNLightTypeOmni

or

if let light = lightNode.light {
    light.type = SCNLightTypeOmni
}

There are other very similar cases where the API has been updated to return Optionals, for example:

theGlobeGeometry.firstMaterial.diffuse.contents = UIImage(named:"earth_diffuse.jpg")
theGlobeGeometry.firstMaterial.ambient.contents = UIImage(named:"earth_ambient2.jpeg")
theGlobeGeometry.firstMaterial.specular.contents = UIImage(named:"earth_specular.jpg")
// etc...

should be changed into

theGlobeGeometry.firstMaterial?.diffuse.contents = UIImage(named:"earth_diffuse.jpg")
theGlobeGeometry.firstMaterial?.ambient.contents = UIImage(named:"earth_ambient2.jpeg")
theGlobeGeometry.firstMaterial?.specular.contents = UIImage(named:"earth_specular.jpg")
// etc...

Note the added ? after firstMaterial, because it's not guaranteed that a geometry object has a material.

Upvotes: 1

Related Questions