You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用SwiftUI Photo Picker上传图片至Firebase?

问题

使用SwiftUI原生图片选择器,选择和加载图片功能正常,但上传至Firebase时,不知道在viewModel.uploadPost(caption: caption, image: <??>)的image参数中传入什么。尝试调用selectedImage,收到错误提示它不是UIImage类型,以为已经在ImagePicker中完成了数据转UIImage的操作,作为Swift新手,希望得到帮助。

UploadPostView

struct UploadPostView: View {
@StateObject var imagePicker = ImagePicker()
@State private var caption = ""
@Environment(\.presentationMode) var mode
@ObservedObject var viewModel = UploadPostViewModel()
        
    var body: some View {
        NavigationView {
            VStack {
                
                HStack(alignment: .top, spacing: 16) {
                    if let user = AuthViewModel.shared.currentUser {
                        KFImage(URL(string: user.profileImageUrl ?? ""))
                            .resizable()
                            .scaledToFill()
                            .frame(width: 64, height: 64)
                            .cornerRadius(10)
                    }
                    TextField("Enter your post here", text: $caption,  axis: .vertical)
                        .lineLimit(5...10)
                }.padding()
                
                Spacer()
                
                if let image = imagePicker.image {
                    HStack {
                        ZStack (alignment: .top) {
                            image
                                .resizable()
                                .scaledToFill()
                                .frame(width: 100, height: 100)
                                .cornerRadius(4)
                            Button {
                                self.imagePicker.image = nil
                            } label: {
                                Image(systemName: "xmark")
                                    .frame(width: 24, height: 24)
                                    .foregroundColor(.white)
                                    .padding(4)
                                    .background(.black)
                                    .clipShape(Circle())
                            }
                            .offset(x: 45, y: -15)
                        }

                        Spacer()
                    }
                    .padding()
                }
                
                HStack (spacing: 24) {
                    Text("Add to your post")
                        .foregroundColor(Color(.darkGray))
                    
                    Spacer()

                    PhotosPicker(selection: $imagePicker.imageSelection) {
                        Image(systemName: "photo")
                            .resizable()
                            .scaledToFit()
                            .frame(width: 24, height: 24)
                    }.foregroundColor(Color(.darkGray))
                    
                    Button {
                        
                    } label: {
                        Image(systemName: "at")
                            .resizable()
                            .scaledToFit()
                            .frame(width: 22, height: 22)
                    }.foregroundColor(Color(.darkGray))
                }
                .padding()
            }
            .onReceive(viewModel.$didUploadPost) { success in
                if success {
                    mode.wrappedValue.dismiss()
                }
            }
            .navigationTitle("Create Post")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button {
                    mode.wrappedValue.dismiss()
                    } label: {
                    Image(systemName: "xmark")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 18, height: 18)
                    .foregroundColor(Color(.darkGray))
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                       viewModel.uploadPost(caption: caption, image: image)) // 问题所在
                    } label: {
                        Text("Post")
                            .font(.system(size: 18))
                            .bold()
                    }
                }
            }
        }
    }
}

UploadPostViewModel

class UploadPostViewModel: ObservableObject {
@Published var didUploadPost = false
@Published var didDeletePost = false
let service = PostService()

func uploadPost(caption :String, image: UIImage?) {
    service.uploadPost(caption: caption, image: image) { success in
        if success {
            //dismiss screen
            self.didUploadPost = true
        } else {
            // show error message to user..
            
        }
    }
}
}

ImagePicker

@MainActor class ImagePicker: ObservableObject {

@Published var image: UIImage?
@Published var imageSelection: PhotosPickerItem? {
    didSet {
        if let imageSelection {
            Task {
                try await loadTransferable(from: imageSelection)
            }
        }
    }
}

func loadTransferable(from imageSelection: PhotosPickerItem?) async throws {
    do {
        if let data = try await imageSelection?.loadTransferable(type: Data.self) {
            if let uiImage = UIImage(data: data) {
                self.image = uiImage
            }
        }
    } catch {
        print(error.localizedDescription)
        image = nil
    }
}
}
解决方案

核心问题是:Toolbar按钮里的image是if let image = imagePicker.image代码块内的局部变量,代码块外部无法访问。而ImagePicker类中已经通过@Published var image: UIImage?保存了转换后的UIImage对象,直接传入这个值即可。

修改Toolbar中Post按钮的代码:

Button {
    viewModel.uploadPost(caption: caption, image: imagePicker.image)
} label: {
    Text("Post")
        .font(.system(size: 18))
        .bold()
}

额外建议:为避免用户未选图就上传,可添加判断逻辑:

Button {
    guard let selectedImage = imagePicker.image else {
        // 此处可添加提示用户选择图片的逻辑
        return
    }
    viewModel.uploadPost(caption: caption, image: selectedImage)
} label: {
    Text("Post")
        .font(.system(size: 18))
        .bold()
}

这样就能正确将选中的UIImage传给上传方法,匹配UploadPostViewModel中uploadPost方法的参数类型。

内容的提问来源于stack exchange,提问作者amelia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 13:10:24