I'm relatively new to Swift and have yet to master the safety aspects of optionals.
I have a dictionary of type [String: [SCNNode]]
. A given molecule will have multiple components as elements in an [SCNNode]
. For that molecule I retrieve this array of components and assign each element to a local SCNNode
to be displayed, manipulated and animated.
let components = moleculeDictionary["aceticAcid"] // the array of components
// [baseMolecule, hydrogenCharge, oxygenCharge, ionizingH, ionizedBond, bonds]
atomsNode_1 = components![0] // baseMolecule
baseNode.addChildNode(atomsNode_1)
atomsNode_5 = components![3] // ionizingH
atomsNode_1.addChildNode(atomsNode_5)
// etc.
In an attempt to optionally bind this, the compiler seems happy with this.
if let node = components?[0] { // baseMolecule
baseNode.addChildNode(node)
}
I'm unclear on the ?. My reading on this suggests we're unwrapping in such a way that we don't care if there's a nil. But does that make this optional binding any better that the forced unwrapping above? Or is this "optional chaining"? Should I be looking instead to just do a check when I assign components
? Should I even be concerened about safety here? The only "upsteam" test I've done is for the presence of the dictionary archive before assigning it to moleculeDictionary
.
I will have hundreds of these assignments so I'd like to get this right. Suggestions on the best way to handle this are welcome!
Thanks, Byrne
In my opinion, you should be worried about safety in Swift. Given your code above I would rewrite it in the first pass as:
guard let components = moleculeDictionary["aceticAcid"] where components.count > 3 else { // handle the case where there is no value for this key, or not enough nodes }
// Now I know that I have the correct number of components I don't need to force unwrap:
atomsNode_1 = components[0] // baseMolecule
baseNode.addChildNode(atomsNode_1)
atomsNode_5 = components[3] // ionizingH
atomsNode_1.addChildNode(atomsNode_5)
That's the first first pass. The second pass would be to make sure that I have values for all the components would be to write a struct to contain the SCNNode
values so that I either had a value or a nil for each node, you could then build up your node structure accordingly.
Edited to add
Here's an indication of the second pass - which really needs more domain knowledge than I have, but it's a start.
It seems you build up the molecules from [[SCNNode]]
(an array of arrays of SCNNode
s where the position of each subarray is significant. It's worth putting this into it's own structure such that:
struct Molecule {
let baseMolecule: [SCNNode]?
let hydrogenCharge: [SCNNode]?
let oxygenCharge: [SCNNode]?
let ionizingH: [SCNNode]?
let ionizedBond: [SCNNode]?
let bonds: [SCNNode]?
// Other methods can be written to build up atom nodes from within the struct which handle the cases where the component array is nil
}