UIImage не передан в функцию

Я пытаюсь собрать фотографии из фотопленки пользователя, отобразить их на экране и, нажав кнопку, выполнить загрузку в Firebase. Однако изображение не загружается.

Я обнаружил, что при передаче изображений в uploadAsJPEG или uploadAsJPEG1x1 (они отображают аналогичные результаты) передается пустой массив, а не массив UIImages.

Когда я выполняю loadImages, показанный ниже в viewModel, фотографии действительно добавляются правильно. Однако при передаче изображений в структуры ImageStorageService в конечном итоге передается пустой массив значений. Почему это происходит и как это исправить?

Я сделал здесь простое тестовое представление, чтобы изолировать проблему, а именно:

      import SwiftUI

struct TestView: View {
    @StateObject private var viewModel = OnboardingViewModel()
    @State private var isUploading = false
    var body: some View {
        VStack {
            ImageSelectorView()
            Button(action: {
                Task {
                    isUploading = true
                    await viewModel.uploadAndUpdateImageURLs(email: "test@test.com", images: viewModel.images)
                    isUploading = false
                }
            }, label: {
                Text("Save Photos")
            })
            if isUploading {
                ProgressView()
            }
        }
    }
}

#Preview {
    TestView()
}

и imageSelectorView:

      import SwiftUI

struct ImageView: View {
    var uiImage: UIImage
    var body: some View {
        Image(uiImage: uiImage)
            .resizable()
            .scaledToFit()
    }
}

struct ImageSelectorView: View {
    //@State private var images: [UIImage] = []
    //@State private var image: Image?
    //@State private var isShowingImagePicker = false
    //@State private var inputImage: UIImage?
    
    @ObservedObject private var viewModel = OnboardingViewModel()
    //@Binding var savedImages: [UIImage]
    
    var body: some View {
        NavigationView {
            VStack {
                ZStack {
                    Rectangle()
                        .fill(Color.secondary)
                    
                    Text("Tap To Select Photos")
                        .foregroundColor(.white)
                        .font(.headline)
                }
                .onTapGesture {
                    viewModel.isShowingImagePicker = true
                }
                HStack {
                    ForEach(viewModel.images.indices, id: \.self) { index in
                        ImageView(uiImage: viewModel.images[index])
                    }
                }
                

            }
            .padding([.horizontal, .bottom])
            .onChange(of: viewModel.inputImage) { _ in
                viewModel.loadImages()
            }
            .sheet(isPresented: $viewModel.isShowingImagePicker) {
                ImagePicker(image: $viewModel.inputImage)
            }
        }
    }
    
    
}

соответствующие компоненты viewModel:

      struct ImageStorageService{
    static private let storage = Storage.storage()
    ///Uploads a multiple images as JPEGs and returns the URLs for the images
    ///Runs the uploads simultaneously
    static func uploadAsJPEG(images: [UIImage], path: String, compressionQuality: CGFloat = 1) async throws -> [URL]{
        return try await withThrowingTaskGroup(of: URL.self, body: { group in
            print("images array incoming is: \(images)")
            print("images array count is: \(images.count)")
            for image in images {
                group.addTask {
                    return try await uploadAsJPEG(image: image, path: path, compressionQuality: compressionQuality)
                }
            }
            var urls: [URL] = []
            for try await url in group{
                urls.append(url)
                print("URLS array is currently: \(urls)")
            }
            
            return urls
        })
    }
    
    ///Uploads a multiple images as JPEGs and returns the URLs for the images
    ///Runs the uploads one by one
    static func uploadAsJPEG1x1(images: [UIImage], path: String, compressionQuality: CGFloat = 1) async throws -> [URL]{
        var urls: [URL] = []
        for image in images {
            let url = try await uploadAsJPEG(image: image, path: path, compressionQuality: compressionQuality)
            urls.append(url)
            print("URLS array is currently: \(urls)")
        }
        return urls
    }
    ///Uploads a single image as a JPG and returns the URL for the image
    ///Runs the uploads simultaneously
    static func uploadAsJPEG(image: UIImage, path: String, compressionQuality: CGFloat = 1) async throws -> URL{
        guard let data = image.jpegData(compressionQuality: compressionQuality) else{
            throw ServiceError.unableToGetData
        }
        
        return try await upload(imageData: data, path: path)
    }
    ///Uploads Data to the designated path in `FirebaseStorage`
    static func upload(imageData: Data, path: String) async throws -> URL{
        let storageRef = storage.reference()
        let imageRef = storageRef.child(path)
        
        let metadata = try await imageRef.putDataAsync(imageData)
        return try await imageRef.downloadURL()
    }
    
    enum ServiceError: LocalizedError{
        case unableToGetData
    }
}

@Published var images: [UIImage] = []
@Published var inputImage: UIImage?

func uploadAndUpdateImageURLs(email: String, images: [UIImage]) async {
        print("uploadAndUpdateImageURLs Reached")
        
        do {
            let imageURLs = try await ImageStorageService.uploadAsJPEG(images: images, path: "users")
            print("ImageURLs is currently: \(imageURLs)")
            print("Count of imageURLs is: \(imageURLs.count)")
            for imageURL in imageURLs {
                await updateImageURLs(email: email, imageURL: imageURL.absoluteString)
            }
        } catch {
            print("error uploading and updating imageURLs: \(error.localizedDescription)")
        }
    }

func loadImages() {
        guard let inputImage = inputImage else { return }
        images.append(inputImage)
        print("images array is currently \(images)")
    }

1 ответ

У вас есть несколькоOnboardingViewModel(), например, в и затем снова вImageSelectorView. Они не имеют никакого отношения друг к другу. У одного есть изображения, а у другого нет.

У вас должен быть только один источник истины — и передавать эту модель другим представлениям.

Например, в вашемTestViewиспользовать:

       ImageSelectorView(viewModel: viewModel)  // <--- here

затем

      struct ImageSelectorView: View {
   //...
   @ObservedObject private var viewModel: OnboardingViewModel  // <--- here
Другие вопросы по тегам