Reputation: 477
I am trying to observe the progress when uploading an image to firebase storage. The progress is being updated in the console however my ProgressView does not update. Everything else seems to be working as expected. Any idea what I'm doing wrong?
class UserManager: ObservableObject {
@Published var taskProgress: Float = 0.0
let user = Auth.auth().currentUser
func uploadProfilePicture(image: UIImage) {
let uploadRef = FirebaseReferenceManager.storage.reference(withPath: "profile/\(user!.uid)")
guard let imageData = image.jpegData(compressionQuality: 0.75) else {
return
}
let uploadMetaData = StorageMetadata.init()
uploadMetaData.contentType = "image/jpeg"
let taskReference = uploadRef.putData(imageData, metadata: uploadMetaData) { (downloadMetaData, error) in
if let error = error {
print(error.localizedDescription)
return
} else {
print("Successfully Uploaded Profile Picture to Firebase Storage")
let downloadRef = FirebaseReferenceManager.storage.reference(withPath: "profile/\(self.user!.uid)")
downloadRef.downloadURL { (url, error) in
if let error = error {
print(error.localizedDescription)
return
}
FirebaseReferenceManager.root.collection(FirebaseKeys.CollectionPath.users).document(self.user!.uid).setData([FirebaseKeys.UsersFieldPath.photoURL : url!.absoluteString], merge: true)
}
}
}
taskReference.observe(.progress) { [weak self] (snapshot) in
DispatchQueue.main.async {
guard let pctThere = snapshot.progress?.fractionCompleted else {return}
print(pctThere)
self?.taskProgress = Float(pctThere)
}
}
taskReference.resume()
}
}
In my view I put the following
@EnvironmentObject var userManager: UserManager
ProgressView(value: userManager.taskProgress).progressViewStyle(LinearProgressViewStyle())
Here is how the class is initialized:
struct SwiftUIView: View {
@StateObject var userManager = UserManager()
var body: some View {
TabView {
HomeView().tabItem {
Image("home")
Text("Home")
}
SearchView().tabItem {
Image("search")
Text("Search")
}
DiscoverView().tabItem {
Image("discover")
Text("Discover")
}
OrdersView().tabItem {
Image("calendar")
Text("Orders")
}
InboxView().tabItem {
Image("inbox")
Text("Inbox")
}
}
.environmentObject(userManager)
}
}
And then I pass it down deeper into the hierarchy using
@EnvironmentObject var userManager: UserManager
Here is where uploadProfilePicture() is called:
struct ImagePicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
@Binding var selectedImage: UIImage
@Environment(\.presentationMode) private var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.delegate = context.coordinator
imagePicker.allowsEditing = true
imagePicker.sourceType = sourceType
return imagePicker
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let parent: ImagePicker
@ObservedObject private var userManager = UserManager()
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.editedImage] as? UIImage {
parent.selectedImage = image
userManager.uploadProfilePicture(image: image)
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
Upvotes: 1
Views: 621
Reputation: 52397
From the comments, we deduced that it was a different UserManager
instance. Here would be an example of how to pass the same instance into the Coordinator
(this is assuming that ImagePicker exists in an environment where @EnvironmentObject var userManager: UserManager
is available).
struct ImagePicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
@Binding var selectedImage: UIImage
@Environment(\.presentationMode) private var presentationMode
@EnvironmentObject private var userManager: UserManager //<-- Here
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.delegate = context.coordinator
imagePicker.allowsEditing = true
imagePicker.sourceType = sourceType
return imagePicker
}
func makeCoordinator() -> Coordinator {
Coordinator(self, userManager: userManager) //<-- Here
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let parent: ImagePicker
let userManager: UserManager
init(_ parent: ImagePicker, userManager: UserManager) { //<-- Here
self.parent = parent
self.userManager = userManager //<-- Here
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.editedImage] as? UIImage {
parent.selectedImage = image
userManager.uploadProfilePicture(image: image)
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
Upvotes: 1