본문 바로가기

UIKIT/Firebase

📍 Firebase 의 Storage 에 사진 업로드하는 방법

✅ Firebase 의 Storage 에 저장하는 메서드

  • images/{userID}/profileImage/profileImage_{userID}.jpg 경로를 사용해서 사용자별로 폴더를 구분
  • 나중에 리뷰 이미지 등 다른 카테고리를 추가할 확장성도 고려
  • 이 메서드는 Firebase Storage에 사용자의 프로필 이미지를 업로드하는 기능을 수행
import Foundation
import FirebaseAuth
import FirebaseStorage
import FirebaseStorageCombineSwift
import Combine


final class StorageManager {
    
    
    // MARK: - Variable
    static let shared = StorageManager()  // ✅ 싱글턴 인스턴스 생성
    
    let storage = Storage.storage()       // ✅ Firebase Storage 인스턴스
    
    func uploadProfilePhotp(with userID: String, image: Data, metaData: StorageMetadata) -> AnyPublisher<StorageMetadata, Error> {
        
        return storage
            .reference()
            .child("images/\(userID)/profileImage/profileImage_\(userID).jpg")  // ✅ 저장 경로 설정
            .putData(image, metadata: metaData)    // ✅ 데이터를 업로드하고 메타데이터 포함       
            .print()                               // ✅ 디버깅 용
            .eraseToAnyPublisher()                 // ✅ Combine을 사용해 AnyPublisher로 변환
    }
    
}

 

🔷 메서드 설명

매개변수

  • userID: String → 사용자의 고유한 ID (폴더 구분용)
  • image: Data → 업로드할 이미지 데이터 (JPEG, PNG 등)
  • metaData: StorageMetadata → 업로드할 파일에 대한 메타데이터

 

🔷 메타데이터(StorageMetadata)란?

StorageMetadata는 Firebase Storage에 업로드할 파일의 추가 정보(메타데이터)를 설정하는 역할을 해.

📌 사용 목적

  1. MIME 타입 지정 (ex: image/jpeg, image/png)
  2. 커스텀 메타데이터 추가 (ex: ["uploader": "user123"])
  3. 캐싱 설정 (ex: 만료 날짜 지정)
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg" // 파일 타입 설정
metaData.customMetadata = ["uploadedBy": "user123", "type": "profile"]

 

🔨 개선할 수 있는 점 

1️⃣ profileImage 폴더의 중복된 의미

 

  • 현재 profileImage 폴더 안에 profileImage_{userID}.jpg라는 파일명을 사용
  • profileImage/profileImage_{userID}.jpg보다는 profile/profile.jpg 같은 형식이 더 직관적일 수도 있음
  • 만약 같은 폴더에 여러 개의 프로필 사진을 저장하고 관리할 예정이라면, 현재 방식도 괜찮음.

2️⃣ 프로필 사진을 덮어쓰기할 경우 고려

  • 현재 방식은 같은 profileImage_{userID}.jpg를 계속 덮어쓰는 구조
  • 혹시 유저가 이전 사진을 유지하고 싶다면, timestamp를 붙여서 버전 관리를 할 수도 있음
images/{userID}/profile/profile_{timestamp}.jpg

🤔 타임스탬프를 사용한 파일명

let timestamp = Int(Date().timeIntervalSince1970) // 현재 시간을 초 단위로 변환

 

📌 타임스탬프를 적용한 파일명 예제

func uploadProfilePhotp(with userID: String, image: Data, metaData: StorageMetadata) -> AnyPublisher<StorageMetadata, Error> {
	
    let timestamp = Int(Date().timeIntervalSince1970) // 현재 시간을 초 단위로 변환
    
    return storage
        .reference()
        .child("images/\(userID)/profileImage/profileImage_\(timestamp).jpg")  // ✅ 저장 경로 설정
        .putData(image, metadata: metaData)    // ✅ 데이터를 업로드하고 메타데이터 포함       
        .print()                               // ✅ 디버깅 용
        .eraseToAnyPublisher()                 // ✅ Combine을 사용해 AnyPublisher로 변환
}

📌 저장 경로 예시 

  • 1709110200은 2025년 2월 28일의 특정 시점을 나타내는 타임스탬프 값
images/user123/reviews/review_abc123_1709110200.jpg

3️⃣ 리뷰 이미지 저장 경로 미리 정의

  • 리뷰 이미지 저장도 고려하고 할 경우, 미리 폴더 구조를 정의해 두면 좋음.
func uploadReviewImage(userID: String, reviewID: String, image: Data, metaData: StorageMetadata) -> AnyPublisher<StorageMetadata, Error> {
    return storage
        .reference()
        .child("images/\(userID)/reviews/review_\(reviewID).jpg") // 리뷰 이미지 저장 경로
        .putData(image, metadata: metaData)
        .print()
        .eraseToAnyPublisher()
}

 

 

✅ 최종 추천 구조

images/
 ├── {userID}/
 │   ├── profile/profile.jpg
 │   ├── reviews/{reviewID}.jpg
 │   ├── posts/{postID}.jpg  (필요하면)
 │   ├── etc/ (기타 필요한 이미지)