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
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
}
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With