Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Whether environmentObject can be accessed by non View subclasses in SwiftUI

Tags:

swift

swiftui

I understand that EnvironmentObjects are for sharing data between the Views. I am curious to know whether it is possible for other non View sub-classes to access EnvironmentObjects and update them. If yes are we breaking any architectural pattern here?
What should be our approach if we need to access EnvironmentObjects in non-View subclasses

Edit-I

I am using AVFoundation to get video frames. After receiving the frames I am trying to update an environmentObject so that all the Views can access the frame. Below is the code:

class Coordinator {

    let delegate = VideoDelegate()
    let controller: CameraController!

    init(){

        controller = CameraController(delegate)
    }
}

final class VideoDelegate: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate{
    @EnvironmentObject var frame: CIImageFrame

    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {

        if let cvImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {

            self.frame.image = CIImage(cvImageBuffer: cvImageBuffer)

        } else {

            //Log message
            print("CMSampleBuffer to CIImage conversion error")
        }
    }
}



//Wrap CIImage to make it EnvironmentObject
final class CIImageFrame: ObservableObject {
   @Published var image = CIImage()
}

The Coordinator object is created in one of the views

like image 281
indra Avatar asked Oct 26 '25 14:10

indra


1 Answers

The EnvironmentObject is just a mechanism to inject instance of reference type confirming to ObservableObject protocol into SwiftUI view hierarchy and update such view if corresponding properties changed, just by observing corresponding publishers. But it is just ordinary reference type instance, you can pass it here and there in the same way how you pass any other reference type instance, and operate with it (properties, functions) as with any other reference type instance.

No magic.

Update: now to code

You don't need to use @EnvironmentObject wrapper in your delegate it is for views, instead use the following (sketch, as your code cut)

class Coordinator {
    let owner: _Owner_Type_     // << here is owner view of coordinator
    let delegate: VideoDelegate
    let controller: CameraController!

    init(owner: _Owner_Type_){
        self.owner = owner

        // owner is view which has @EnvironmentObject property, 
        // so use it here to pass into VideoDelegate
        delegate = VideoDelegate(frame: owner.frame)

        controller = CameraController(delegate)
    }
}

final class VideoDelegate: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate{
    private var frame: CIImageFrame // just reference member

    // now your delegate has reference to the same instance as environment
    // object in view
    init(frame: CIImageFrame) {
       self.frame = frame
    }
    ...

like image 121
Asperi Avatar answered Oct 28 '25 03:10

Asperi