1

I've a little trouble with implement a changeText function. PlaneDetection works, the first text displayed correctly. Once I hit on the button which linked to the changeText() function and it stop working. The error shows something about unwrapping optional value with arView, I tried everything I could still didn't work at all.

Error:

AR3DText/ContentView.swift:18: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value 2021-10-24 13:18:53.331758-0700 AR3DText[8026:2401109] AR3DText/ContentView.swift:18: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value (lldb)

import SwiftUI
import RealityKit
import ARKit

struct ContentView : View {
  var body: some View {
    return ARViewContainer()
      .overlay(
        VStack{
          Spacer()
          Button(action:{arView.changeText("Frank is awesome")}) {
            Text("Change Text")
              .frame(width:120,height:40)
              .font(.body)
              .foregroundColor(.black)
              .background(Color.white)
              .opacity(0.6)
          }
          .offset(y:-30)
          .padding(.bottom, 30)
        }
    )
      .edgesIgnoringSafeArea(.all)
  }
}

struct ARViewContainer: UIViewRepresentable {
   
  func makeUIView(context: Context) -> ARView {
     
    let arView = ARView(frame: .zero)
    let config = ARWorldTrackingConfiguration()
    config.planeDetection = .horizontal
    arView.session.run(config, options: [])
    arView.session.delegate = arView
    arView.createPlane()
    return arView
     
  }
   
  func updateUIView(_ uiView: ARView, context: Context) {}
   
}


var textElement = TextElements()
var textEntity: ModelEntity!
var planeAnchor: AnchorEntity!


extension ARView: ARSessionDelegate {
  func createPlane() {
    let planeAcnchor = AnchorEntity(plane: .horizontal)
    let textMesh: MeshResource = .generateText("Hello Frank!", extrusionDepth: textElement.extrusionDepth, font: textElement.font, containerFrame: CGRect(), alignment: .left, lineBreakMode: .byWordWrapping)
    let textMaterial = SimpleMaterial(color: textElement.textColor, isMetallic: true)
    let textEntity = ModelEntity(mesh: textMesh, materials: [textMaterial])
    textEntity.generateCollisionShapes(recursive: false)
    planeAcnchor.addChild(textEntity)
    self.scene.addAnchor(planeAcnchor)
    self.installGestures(.all, for: textEntity)
  }
   
  func changeText(_ textContent: String) {
    let textMesh: MeshResource = .generateText(textContent, extrusionDepth: textElement.extrusionDepth, font: textElement.font, containerFrame: CGRect(), alignment: .left, lineBreakMode: .byWordWrapping)
    let textMaterial = SimpleMaterial(color: .blue, isMetallic: false)
    textEntity.removeFromParent()
    let textEntity = ModelEntity(mesh: textMesh, materials: [textMaterial])
    planeAnchor.addChild(textEntity)
    self.scene.addAnchor(planeAnchor)
    self.installGestures(.all, for: textEntity)
     
     
  }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
#endif
Frank Lan
  • 103
  • 5
  • Declaring things like `var arView: ARView!` *outside* of your structs/classes is generally not a good idea. Check out [this answer](https://stackoverflow.com/a/65926143/560942) of mine about communicating with a `UIViewController` from a SwiftUI button – jnpdx Oct 28 '21 at 00:33
  • Ask a search engine about "Unexpectedly found nil while implicitly unwrapping an Optional value" – El Tomato Oct 28 '21 at 00:41

1 Answers1

0

The problem like this is that you've created a global variable (non-optional) for arView, but then you initialize a new one via makeUIView and never call that method or set the global instance of arView. When you button code executes, arView was never initialized, and thus is nil.

While I agree with the other comments that there are better ways to architect this, you just need to make sure you initialize that view before any of the code that references it executes.

brandonscript
  • 68,675
  • 32
  • 163
  • 220