This problem occasionally happens. My view looks like this simplified:
struct CameraView: View {
@State var camera: Camera
var body: some View {
VStack{
if let uiImage = camera.previewPhoto {
ImageView(uiImage)
SomeOtherButton()
} else {
camera.preview
CapturePhotoButton(camera) // has a button that calls camera.capturePhoto()
}
}
}
}
And I have a Camera
view model that looks something like this:
@Observable
class Camera {
@ObservationIgnored private let captureSession: MyCustomCaptureSession
@ObservationIgnored @MainActor var preview: some View {
captureSession.preview // Just a wrapper view around AVCaptureVideoPreviewLayer
}
@MainActor var previewPhoto: UIImage?
@MainActor func capturePhoto() async {
// Take a photo using a captureSession
print("AT POINT A")
previewPhoto = capturedPhoto
}
}
As you can see, I made sure to decorate previewPhoto
with @MainActor
.
On some rare occasions, when I press the “capturePhoto” button (not show here), I see the line AT POINT A
get printed, but the view does not update. This baffles me and is really hard to debug, any ideas?
One thing I noticed is that if I break up the CameraView
into top and bottoms halves:
struct CameraView: View {
@State var camera: Camera
var body: some View {
VStack{
if let uiImage = camera.previewPhoto {
ImageView(uiImage)
} else {
camera.preview
}
if let uiImage = camera.previewPhoto {
SomeOtherButton()
} else {
CapturePhotoButton(camera) // has a button that calls camera.capturePhoto()
}
}
}
}
The view will sometimes only update the bottom, not the top, this makes me suspect its some kind of race condition or that it’s related to camera.preview
.
Another thing to note is that I’m using iOS 17’s new observation framework.