I am working on a SwiftUI project that is using a UIImagePickerController through UIViewControllerRepresentable. In the UIViewControllerRepresentable file I add the following line so that I can dismiss the ImagePicker in imagePickerController didFinishPickingMediaWithOptions method.
@Environment(\.presentationMode) var presentationMode
In my view file I would also like to be able to dismiss the view so I add the line.
@Environment(\.presentationMode) var presentaionMode: Binding<PresentationMode>
However, when this line is added to the view, it causes the ActionSheet to be created four time. Once an item is selected from the ActionSheet it is called twice more. The print statement ShowSheetButtons is how I've identified it being called multiple times. If this @Environment line is removed, all performs as expected. Is there a reason this is happening and how can I fix it. I'd like to be able to use presentationMode in both the View and the UIViewControllerRpresentable.
View
struct CreateListingView: View {
// MARK: ++++++++++++++++++++++++++++++++++++++ Properties ++++++++++++++++++++++++++++++++++++++
// Dismiss the View
@Environment(\.presentationMode) var presentaionMode: Binding<PresentationMode>
// Media Picker
@State var showMediaPickerSheet = false
@State var showLibrary = false
@State var showMediaErrorAlert = false
@frozen enum MediaTypeSource {
case library
}
// MARK: ++++++++++++++++++++++++++++++++++++++ View ++++++++++++++++++++++++++++++++++++++
var body: some View {
return
Button(action: {
self.presentMediaPicker()
}, label: {
Text("Button")
})
.actionSheet(isPresented: $showMediaPickerSheet, content: {
ActionSheet(
title: Text("Add Store Picture"),
buttons: sheetButtons()
)
}) // Action Sheet
.sheet(isPresented: $showLibrary, content: {
MediaPickerPhoto(sourceType: .photoLibrary, showError: $showMediaErrorAlert) { (image, error) in
if error != nil {
print(error!)
} else {
guard let image = image else {
return
}
}
}
})
} // View
// MARK: ++++++++++++++++++++++++++++++++++++++ Methods ++++++++++++++++++++++++++++++++++++++
// Media Picker Methods
func presentMediaPicker() {
print("PresentMediaPicker1Listing")
self.showMediaPickerSheet = true
}
func sheetButtons() -> [Alert.Button] {
print("ShowSheetButtonsListing")
return UIImagePickerController.isSourceTypeAvailable(.camera) ? [
.default(Text("Choose Photo")) {
presentMediaPicker1(.library)
},
.cancel {
showMediaPickerSheet = false
}
] : [
.default(Text("Choose Photo")) {
presentMediaPicker1(.library)
},
.cancel {
showMediaPickerSheet = false
}
]
}
private func presentMediaPicker1(_ type: MediaTypeSource) {
print("PresentMediaPicker2Listing")
showMediaPickerSheet = false
switch type {
case .library:
showLibrary = true
}
}
}
UIViewControllerRepresentable
struct MediaPickerPhoto: UIViewControllerRepresentable {
typealias UIViewControllerType = UIImagePickerController
/// Presentation wrapper
@Environment(\.presentationMode) var presentationMode
/// Source type to present for
let sourceType: UIImagePickerController.SourceType
/// Binding for showing error alerts
@Binding var showError: Bool
/// Callback for media selection
let completion: (UIImage?, String?) -> Void
// MARK: - Representable
func makeUIViewController(context: UIViewControllerRepresentableContext<MediaPickerPhoto>) -> UIImagePickerController {
print("MakeUIViewController")
let picker = UIImagePickerController()
if sourceType == .camera {
picker.videoQuality = .typeMedium
}
picker.sourceType = sourceType
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<MediaPickerPhoto>) {
// no-op
}
// MARK: - Coordinator
func makeCoordinator() -> MediaCoordinatorPhoto {
return Coordinator(self)
}
}
/// Coordinator for media picker
class MediaCoordinatorPhoto: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
// AuthSession
@EnvironmentObject var authSession: AuthSession
let db = Firestore.firestore()
/// Parent picker
let parent: MediaPickerPhoto
// MARK: - Init
init(_ parent: MediaPickerPhoto) {
print("MediaCoordinatorPhoto")
self.parent = parent
}
// MARK: - Delegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let type = (info[.mediaType] as? String)?.lowercased() else {
return
}
if type.contains("image"), let uiImage = info[.originalImage] as? UIImage {
// We attempt to resize the image to max os 1280x1280 for perf
// If it fails, we use the original selection image
let image = uiImage.resized(maxSize: CGSize(width: 1280, height: 1280)) ?? uiImage
self.parent.completion(image, nil)
} else {
print("Invalid media type selected")
let error = "There was an error updating your user profile picture. Please try again later."
parent.completion(nil, error)
//parent.showError = true
}
parent.presentationMode.wrappedValue.dismiss()
}
}
Edited
2021-11-03 17:20:13.799510-0700 Global Store Exchange[6900:1991500] [lifecycle] [u
478AD6F6-A9E2-4FE9-96D0-D310B754DD59:m (null)] [com.apple.mobileslideshow.photo-picker(1.0)] Connection to plugin interrupted while in use. 2021-11-03 17:20:13.800173-0700 Global Store Exchange[6900:1990765] viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted} 2021-11-03 17:20:13.800383-0700 Global Store Exchange[6900:1990765] [UI] -[PUPhotoPickerHostViewController viewServiceDidTerminateWithError:] Error Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted} 2021-11-03 17:20:13.800987-0700 Global Store Exchange[6900:1990765] viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted} 2021-11-03 17:20:13.801016-0700 Global Store Exchange[6900:1990765] [UI] -[PUPhotoPickerHostViewController viewServiceDidTerminateWithError:] Error Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted} 2021-11-03 17:20:13.801089-0700 Global Store Exchange[6900:1990765] UIImagePickerController UIViewController create error: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.mobileslideshow.photo-picker.viewservice" UserInfo={NSDebugDescription=connection to service named com.apple.mobileslideshow.photo-picker.viewservice} 2021-11-03 17:20:13.801266-0700 Global Store Exchange[6900:1990765] viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted} 2021-11-03 17:20:13.801313-0700 Global Store Exchange[6900:1990765] [UI] -[PUPhotoPickerHostViewController viewServiceDidTerminateWithError:] Error Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted} 2021-11-03 17:20:13.801421-0700 Global Store Exchange[6900:1990765] viewServiceDidTerminateWithError:: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted} 2021-11-03 17:20:13.801459-0700 Global Store Exchange[6900:1990765] [UI] -[PUPhotoPickerHostViewController viewServiceDidTerminateWithError:] Error Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "(null)" UserInfo={Message=Service Connection Interrupted}