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