Firebaseのセットアップは完了している前提です 🙏
アーキテクチャはガン無視してます。
Firebaseコンソールで、Storage項目でimages/
フォルダを作成しておいてください。
Contents 非表示
実装
ImagePicker.swift (画像選択用)
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
@Binding var image: UIImage?
func makeUIViewController(context: Context) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
let parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let uiImage = info[.originalImage] as? UIImage {
parent.image = uiImage
}
picker.dismiss(animated: true)
}
}
}
HomeView.swift (メインのView)
import SwiftUI
import FirebaseStorage
struct HomeView: View {
@State private var selectedImage: UIImage?
@State private var isImagePickerPresented = false
@State private var imageUrls: [URL] = []
@State private var showUploadView = false
private let storage = Storage.storage()
var body: some View {
NavigationView {
VStack {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(imageUrls, id: \.self) { url in
AsyncImage(url: url) { phase in
if let image = phase.image {
image
.resizable()
.scaledToFill()
.frame(width: 240, height: 240)
} else {
ProgressView("Loading Images...")
}
}
}
}
}
Button("画像を選択") {
isImagePickerPresented = true
}
.sheet(isPresented: $isImagePickerPresented) {
ImagePicker(image: $selectedImage)
}
// 画像が選択されたら、UploadImageViewに遷移する
NavigationLink(
destination: UploadImageView(image: selectedImage ?? UIImage()),
isActive: $showUploadView
) {
EmptyView()
}
.onChange(of: selectedImage) { newImage in
if newImage != nil {
showUploadView = true
}
}
}
.onAppear {
fetchImageUrls()
}
}
}
// 画像のURLをFirebase Storageから取得
private func fetchImageUrls() {
let storageRef = storage.reference().child("images")
storageRef.listAll { result, error in
if let error = error {
print("Error listing images: \(error)")
return
}
guard let items = result?.items else { return }
for item in items {
item.downloadURL { url, error in
if let error = error {
print("Error getting download URL: \(error)")
return
}
// すでに同じURLがリストに存在しないかを確認
if let url = url, !imageUrls.contains(url) {
imageUrls.append(url)
}
}
}
}
}
}
UploadImageView.swift (画像アップロード用)
import SwiftUI
import FirebaseStorage
struct UploadImageView: View {
var image: UIImage
@Environment(\.presentationMode) var presentationMode
@State private var isUploading = false
@State private var uploadSuccess = false
private let storage = Storage.storage()
var body: some View {
VStack(spacing: 24) {
Image(uiImage: image)
.resizable()
.scaledToFill()
.frame(width: 240, height: 240)
.padding()
if isUploading {
ProgressView("Uploading...")
} else {
Button("アップロード") {
uploadImage()
}
}
}
.alert(isPresented: $uploadSuccess) {
Alert(
title: Text("アップロード成功"),
message: Text("画像が正常にアップロードされました"),
dismissButton: .default(Text("OK")) {
// アップロード成功後、HomeViewに戻る
presentationMode.wrappedValue.dismiss()
}
)
}
}
private func uploadImage() {
guard let imageData = image.jpegData(compressionQuality: 0.8) else { return }
isUploading = true
let storageRef = storage.reference().child("images/\(UUID().uuidString).jpg")
storageRef.putData(imageData, metadata: nil) { metadata, error in
isUploading = false
if let error = error {
print("Error uploading image: \(error)")
return
}
storageRef.downloadURL { url, error in
if let error = error {
print("Error getting download URL: \(error)")
return
}
if let _ = url {
uploadSuccess = true
}
}
}
}
}