如何将JSON中DebugOption布尔值高效转为ARkit的SCNDebugOptions数组?
Hey there! I’ve got a clean, scalable solution for converting your JSON debug options to SCNDebugOptions without all the repetitive if-statements you’re probably dealing with. The core idea is to use a mapping system that links your JSON keys directly to their corresponding ARKit enum values—making the code maintainable and easy to extend.
Step 1: Define a Mapping Dictionary
First, create a static dictionary that pairs each JSON debug key from your debugOptions object with the matching SCNDebugOptions case. This keeps all your mappings in one easy-to-update place:
private let debugOptionMap: [String: SCNDebugOptions] = [ "showPhysicsShapes": .showPhysicsShapes, "showBoundingBoxes": .showBoundingBoxes, "showLightInfluences": .showLightInfluences, "showLightExtents": .showLightExtents, "showPhysicsFields": .showPhysicsFields, "showWireframe": .showWireframe, "renderAsWireframe": .renderAsWireframe, "showSkeletons": .showSkeletons, "showCreases": .showCreases, "showConstraints": .showConstraints, "showCameras": .showCameras ]
Step 2: Add a Conversion Method to Your DebugOption Struct
Extend your existing DebugOption struct with a method to convert its boolean properties into a SCNDebugOptions set. I’ll share two approaches—pick the one that fits your style:
Option A: Type-Safe KeyPath Approach (Recommended)
This uses Swift’s KeyPath feature to safely access your struct’s properties, with compile-time checks to avoid typos or missing properties:
extension DebugOption { func toSCNDebugOptions() -> SCNDebugOptions { var enabledOptions: SCNDebugOptions = [] for (key, scnOption) in debugOptionMap { let propertyPath = keyToKeyPath(key) if self[keyPath: propertyPath] { enabledOptions.insert(scnOption) } } return enabledOptions } private func keyToKeyPath(_ key: String) -> KeyPath<DebugOption, Bool> { switch key { case "showPhysicsShapes": return \.showPhysicsShapes case "showBoundingBoxes": return \.showBoundingBoxes case "showLightInfluences": return \.showLightInfluences case "showLightExtents": return \.showLightExtents case "showPhysicsFields": return \.showPhysicsFields case "showWireframe": return \.showWireframe case "renderAsWireframe": return \.renderAsWireframe case "showSkeletons": return \.showSkeletons case "showCreases": return \.showCreases case "showConstraints": return \.showConstraints case "showCameras": return \.showCameras default: fatalError("Unrecognized debug option key: \(key)") } } }
Option B: Mirror Reflection (Shorter Code)
If you don’t mind a tiny bit of runtime overhead (negligible for this use case), you can use Swift’s Mirror to inspect the struct’s properties dynamically:
extension DebugOption { func toSCNDebugOptions() -> SCNDebugOptions { var enabledOptions: SCNDebugOptions = [] let mirror = Mirror(reflecting: self) for (key, scnOption) in debugOptionMap { if let property = mirror.children.first(where: { $0.label == key }), let isEnabled = property.value as? Bool, isEnabled { enabledOptions.insert(scnOption) } } return enabledOptions } }
Step 3: Use the Conversion Method
Once you’ve parsed your JSON into a DebugOption instance via your SceneSettingsFactory, converting is as simple as:
// Assume you have a parsed DebugOption instance from your JSON let parsedDebugOptions = sceneSettings.debugOptions let scnDebugOptions = parsedDebugOptions.toSCNDebugOptions() // Assign to your SCNView scnView.debugOptions = scnDebugOptions
Why This Is Better Than Tedious Conditionals
- Scalable: Adding a new debug option only requires updating the
debugOptionMapand yourDebugOptionstruct—no extra if-statements needed. - Maintainable: All mappings live in one place, so you don’t have to hunt through multiple lines of code to update a key-to-option link.
- Less Error-Prone: The KeyPath approach catches typos at compile time, avoiding runtime bugs from misspelled property names.
内容的提问来源于stack exchange,提问作者Wrumble

