Handling one-time immutable data created by app
Asked Answered
C

1

1

I'm rewriting my app to incorporate SceneKit to display molecules. About 60% of my code is dedicated to creating these molecules as SCNNode arrays stored in a dictionary. Another 20% creates a String dictionary for text display. Ideally, these dictionaries need only be created once.

Currently I'm creating these dictionaries by calls from viewDidLoad in my main (and initial) VC. I then archive the dictionaries:

NSKeyedArchiver.archiveRootObject(moleculeDictionary, toFile: filePath)

I then read the archived dictionary back into a local dictionary that is used by the app:

moleculeDictionary = Molecules.readFile() as! [String: [SCNNode]]

// and in Molecules, the readFile() function:
let dictionary = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath) as? NSDictionary ?? NSDictionary()
return dictionary

I read it from the archive in case the local version is no longer extant. I still need to add a check for the existance of the dictionary.

My question: Is this the best way to do this? Surely this is a common aspect of many programs. My inclination is to create permanent files with these dictionaries during development and include them in the shipped bundle. But no one has responded to my posts on this aspect so I'm thinking everyone does it some other way. I'm praying I don't have to learn about CoreData but if so, let me know.

Clumsy answered 25/2, 2016 at 17:11 Comment(0)
W
3

Instead of archiving/loading an array of dictionaries of multiple node trees, you can work with the scene archives and node archives individually, embedding them within your binary.

If it's a full scene, put it in the art.scnassets folder within your Xcode project, and load it with

        let scene = SCNScene(named: "art.scnassets/oneMolecule.scn")!

That's appropriate if you've archived an entire scene, with nodes, lights, cameras, and actions.

You can archive just one node tree with

let documentDirURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
if let gizmoNode = gameView.scene?.rootNode.childNodeWithName("Gizmo", recursively:true) {
    let gizmoData = NSKeyedArchiver.archivedDataWithRootObject(gizmoNode)
    let gizmoURL = documentDirURL.URLByAppendingPathComponent("Gizmo").URLByAppendingPathExtension("plist")
    print("gizmo path:", gizmoURL.path)
    if (!gizmoData.writeToURL(gizmoURL, atomically: true)) {
        return false
    }
}

If you're using an auxiliary iOS program to generate your assets, they'll be in a Documents folder within your simulator's file hierarchy. If these are on-the-fly generated by your final product, they belong in a cache or temporary folder so that they can be purged if needed and won't be backed up.

If you're shipping the pre-built node, drop it into your project just like a PNG. Fetch it with

let path = NSBundle.mainBundle().pathForResource("Gizmo", ofType: "plist")
print(path)
let gizmoNode = NSKeyedUnarchiver.unarchiveObjectWithFile(path!) as! SCNNode
print (gizmoNode)
scene.rootNode.addChildNode(gizmoNode)

One more thing: building and archiving SCNScenes and SCNNodes doesn't require an SCNView. You can extract the node generation code to a standalone command line Mac program. Build your node trees, archive them individually. Then put them into a scene, archive that, and preview with the Scene Editor. You could automate the entire generate molecules/copy/build iOS app process.

Welles answered 1/3, 2016 at 5:18 Comment(1)
Thank you much, Hal. It all worked great, plays better with memory and uses less code. You managed to answer my big three questions in one response.Clumsy

© 2022 - 2024 — McMap. All rights reserved.