ios – Cannot access Swift Variable in Delegate of ReactNative Native UI Element


I use a Native Camera View from Swift within my React Native app. Within the delegate Methods of my Camera View I check frames etc. I decided to build it as the following:
React Native Main Class of my App:

...
import CamView from './CamView.js';
...
class CamScreen extends Component {
...
   render() {
...
      return(
...
         <CamView style={[styles.camStyle]}/>
...
      )
   }
...
}
...

And my CamView.js is the following:

import { requireNativeComponent } from "react-native";

module.exports = requireNativeComponent("RCTCameraView");

From which I use my Camera Manager:

...
@objc(RCTCameraViewManager)
class CameraViewManager: RCTViewManager {
    var sharedCamView: CamView { return CamView.shared() }
    override static func requiresMainQueueSetup() -> Bool { return true }
    override static func moduleName() -> String! { return "CameraViewManager" }
    override func view() -> UIView! { return sharedCamView }
    override func constantsToExport() -> [AnyHashable : Any] { return ["sharedCamView": sharedCamView.reactTag] }
}

And now my Camera View swift code:

@objc(CamView)
class CamView: UIView, RCTBridgeModule, AVCaptureVideoDataOutputSampleBufferDelegate, AVCapturePhotoCaptureDelegate{
...
var isSessionRunning = false
...
override init(frame: CGRect) {
    super.init(frame: frame)
    self.initializeLibraryFunctions()
    self.setupView()
    if(self.sessionSetup != .success) {
      self.setupSession()
    }
  }
deinit {
    self.session?.stopRunning()
    self.isSessionRunning = false
    self.videoOutput!.setSampleBufferDelegate(nil, queue: nil)
  } 

  override func willMove(toSuperview newSuperview: UIView?) {
    super.willMove(toSuperview: newSuperview)
    if newSuperview != nil {
        self.startSession()
    } else {
        self.stopSession()
    }
  }
...
// start session
  func startSession() {
      if self.isSessionRunning == false && self.sessionSetup == .success {
        if self.session!.isRunning == false {
          // self.videoOutput!.setSampleBufferDelegate(self, queue: self.captureQueue)
          self.session!.startRunning()
          self.isSessionRunning = true
        }
      }
  }
// stop session
  func stopSession() {
      if self.isSessionRunning == true && self.sessionSetup == .success {
        if self.session!.isRunning == true {
          // self.videoOutput!.setSampleBufferDelegate(nil, queue: nil)
          self.session!.stopRunning()
          self.isSessionRunning = false
        }
      }
  }
}
@objc 
func resetCapture() -> Void{
   // I want to print the status here if my session is running
   RNEventEmitter.emitter.sendEvent(withName: "myEventName", body:"isSessionRunning: \(self.isSessionRunning)")
}
...
func setupSession() {
    if(self.sessionHasBeenSetup == true) { return }
    checkPermissions()
    self.session = AVCaptureSession()

    self.videoPreviewLayer.session = self.session
    self.videoPreviewLayer.videoGravity = .resizeAspectFill
    self.videoPreviewLayer.frame = self.layer.bounds

    self.videoOutput = AVCaptureVideoDataOutput()
    self.photoOutput = AVCapturePhotoOutput()
    self.session!.beginConfiguration()
    // set up device
    guard let device = AVCaptureDevice.default(for: .video) else { 
      self.sessionSetup = .failure
      self.session!.commitConfiguration()
      return
    }
    if device.isFocusModeSupported(.continuousAutoFocus) {
      try! device.lockForConfiguration()
      device.focusMode = .continuousAutoFocus
      device.unlockForConfiguration()
    }
    // set up input
    do {
      let input = try AVCaptureDeviceInput(device: device)
      if self.session!.canAddInput(input) {
        self.session!.addInput(input)
      } else {
        self.sessionSetup = .failure
        self.session!.commitConfiguration()
        return
      }
    } catch {
      self.sessionSetup = .failure
      self.session!.commitConfiguration()
      return
    }
    // set video output
    // "com.example.CamViewQueue" is an example for my actual queue which is the same as the queue when I check from resetCapture
    let myQueue = DispatchQueue(label: "com.example.CamViewQueue", attributes: DispatchQueue.Attributes.concurrent)
    self.videoOutput!.setSampleBufferDelegate(self, queue: myQueue)
    
    if self.session!.canAddOutput(self.videoOutput!) {
      self.session!.addOutput(self.videoOutput!)
    } else {
      self.sessionSetup = .failure
      self.session!.commitConfiguration()
      return
    }
    // set up photo output
    if self.session!.canSetSessionPreset(.photo) { session!.sessionPreset = .photo }
    
    if self.session!.canAddOutput(self.photoOutput!) {
      self.session!.addOutput(self.photoOutput!)
    } else {
      self.sessionSetup = .failure
      self.session!.commitConfiguration()
      return
    }
    self.session!.commitConfiguration()
    self.sessionSetup = .success
  }
...
// Delegate Methods
  public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
      if captureInProgress == false && processingImage == false {
        // printing thread name results in the same as in resetCapture: Thread.current.threadName
        // printing isSessionRunning here results in true while in resetCapture it shows false
        RNEventEmitter.emitter.sendEvent(withName: "myEventName", body:"isSessionRunning: \(self.isSessionRunning)")
        processingImage = true // block for entering
        let group = DispatchGroup()
        group.enter()
        DispatchQueue.main.async{
          patternStatus = self.myProcessingFunction(sampleBuffer: sampleBuffer)
          group.leave()
        }
        group.wait()
        group.notify(queue: .main) {
            // do stuff here
          } else {
            self.processingImage = false
          }
        }
    }
  }

Why does printing isSessionRunning results to true within my delegate but from the outside it is false when I invoke resetCapture from my Reactnative App by pushing a button? Both operations are from the same Queue and I think both are from the same CamView instance as far as I understand.
Also when I compare my sessions

self.videoPreviewLayer.session == self.session 

within my resetCapture function both are equal. What I want to do with my resetCapture is to start (and if possible stop and then start) my session. But if I forcefully use self.session.stopRunning() the CamView freezes (but the delegate output gets printed).

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img