🍏

SwiftUIでFirebaseStorageに画像をupload

2024/05/14に公開

🤔やってみたいこと

FirebaseStorageに画像をアップロードして、Cloud Firestoreに画像のパスを保存する処理をSwiftUIに実装したい。

知識がある人前提で記事書いてますので、iOS専用のFirebase SDKをSwift Package Managerを使って追加してください。 
https://firebase.google.com/docs/storage/ios/start?hl=ja

🚀やってみたこと

今回は、ソースコードを全部同じファイルに書いてしまって長くなりましたが、これでよくあるアップロードの機能は作ることができます。

import SwiftUI
import FirebaseStorage
import FirebaseFirestore
import UIKit

class ImagePickerViewModel: ObservableObject {
    @Published var image: UIImage?
    @Published var imagePath: String = ""
    
    func uploadImage() async {
        guard let image = image else { return }
        guard let data = image.jpegData(compressionQuality: 0.5) ?? image.pngData() else { return }
        
        let storage = Storage.storage()
        let storageRef = storage.reference()
        let imageRef = storageRef.child("image/\(UUID().uuidString)")
        
        do {
            let _ = try await imageRef.putData(data, metadata: nil)
            self.imagePath = imageRef.fullPath
            await saveImagePathToFirestore()
        } catch {
            print("Error uploading image: \(error)")
        }
    }
    
    func saveImagePathToFirestore() async {
        let db = Firestore.firestore()
        do {
            try await db.collection("photos").document().setData(["path": self.imagePath])
        } catch {
            print("Error saving image path to Firestore: \(error)")
        }
    }
}

struct ContentView: View {
    @StateObject private var viewModel = ImagePickerViewModel()
    @State private var isImagePickerPresented = false
    
    var body: some View {
        VStack {
            Rectangle()
                .fill(Color.gray)
                .frame(width: 200, height: 200)
                .overlay(
                    Image(uiImage: viewModel.image ?? UIImage())
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                )
                .onTapGesture {
                    isImagePickerPresented = true
                }
            
            Button("Save Image") {
                Task {
                    await viewModel.uploadImage()
                }
            }
            .padding(.top, 20)
        }
        .sheet(isPresented: $isImagePickerPresented) {
            ImagePicker(image: $viewModel.image, isPresented: $isImagePickerPresented)
        }
    }
}

struct ImagePicker: UIViewControllerRepresentable {
    @Binding var image: UIImage?
    @Binding var isPresented: Bool
    
    func makeUIViewController(context: Context) -> some UIViewController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        return picker
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: ImagePicker
        
        init(_ parent: ImagePicker) {
            self.parent = parent
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let image = info[.originalImage] as? UIImage {
                parent.image = image
            }
            parent.isPresented = false
        }
        
        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            parent.isPresented = false
        }
    }
}

Firebase Storageに、imageフォルダを作ってください。ここに保存します。Cloud Firestoreも使えるようにしておいてください。




🙂最後に

今回はざっくりとですが、Firebase Storageで画像のアップロードをする機能を実装してみました。まさかUIKitが必要とは...
別のロジック作った時はいらなかった気がしますが。凝ったUIにするなら、UIKitの知識は求められるそうです。
僕も勉強してますがよくわからないです。強強さんによると、使って覚えるのだろか?

Discussion