Swift 일기장 개발 일기 11 (Firebase Storage 이미지 가져오기)

송민준·2023년 1월 27일
0

일기장 개발 일기

목록 보기
11/11

업로드했던 이미지를 다시 불러오는 작업을 해보겠습니다.
이에 앞서 이미지가 업로드 될 때까지 어떤 작업들이 이루어지는 지 정리해보겠습니다.

  1. 로그인 화면에서 로그인
  2. 메인 화면 넘어가기 전에 이미지를 제외한 일기의 리스트를 전부 가져옴
  3. 메인 화면으로 넘어가고 테이블 뷰에서 셀을 인스턴스화 할 때 이미지를 로드

일기 리스트를 가져올 때 이미지를 로드하지 않은 이유는 이미지를 가져오는 작업이 너무 느려서 동기적으로 리스트를 구성하지 않고 셀을 인스턴스화 할 때 비동기적으로 이미지를 불러오게 하기 위함입니다.

이런 식으로 로드되지 않은 이미지는 기본(로딩) 이미지로 대체하고 로드된 이미지는 원본 이미지가 되도록.

StorageViewModel

import Foundation
import FirebaseStorage
class StorageViewModel : NSObject {
    let storage = Storage.storage()
    ...
    func getImage(uID:String, docID: String, completion: @escaping (Data?) -> Void){
        let storagePath = "gs://futurediary-12345.appspot.com/\(uID)/\(docID).jpg"
        let storageRef = storage.reference(forURL: storagePath)
        storageRef.getData(maxSize: Int64(100 * 1024 * 1024)){(data, error) in
            if let error = error{
                print("Error Occured in getting image : \(error)")
                completion(nil)
            }
            else{
                completion(data!)
            }
        }
    }
    ...
}
  • func getImage : uID와 docID를 통해서 유저의 일기 하나에 할당된 이미지를 불러오는 합수입니다.
    • let storagePath = "gs://futurediary-12345.appspot.com/\(uID)/\(docID).jpg": 이미지의 경로입니다. 이 경로로 레퍼런스를 얻고
    • getData(maxSize:..를 통해 이미지 데이터를 받습니다.
      • 여기서 maxSize를 각자 프로젝트에서 사용하는 이미지에 따라 조정해야지 maximum size가 원본 사이즈보다 작아서 에러가 날 일은 없습니다.

DBViewModel

이 뷰모델을 수정하는 이유는 사진이 포함된 일기는 메인 화면으로 전환되기 전에 "일단" 로딩 이미지로 바꾸기 위함입니다.

import Foundation
import FirebaseFirestore

class DBViewModel : NSObject {
    ...
    func getDiaryList(uID:String, addingClosure:@escaping (Diary) -> Void, completeClosure:@escaping ()->Void){
        db.collection("users").document(uID).collection("diarys").getDocuments(completion:{ (querySnapshot, error) in
            if let error = error {...}
            else {
                if let querySnapshot = querySnapshot {
                    ...
                    for i in 0 ..< querySnapshot.documents.count{
                        ...
                        if docData["haveImage"] as! Bool {
                            
                            ...
                            let loadImg = UIImage(named: "load-icon-png-8")!.pngData()!
                            ...
                        }
                        else{
                            ...
    }
    ...
}
  • let loadImg = UIImage(named: "load-icon-png-8")!.pngData()!: 프로젝트 내부에 저장한 이미지를 pngData로 변형시킵니다. 어느 위치에서든 저 파일을 가져오는게 신기합니다.

MainVC

...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "diaryCell", for: indexPath) as? DiaryTableViewCell else {return UITableViewCell()}
        ...
        if let imageData = cell.cellData.imageData{
            cell.diaryTableViewCellImage.isHidden = false
            cell.diaryTableViewCellImage.image = UIImage(data: imageData)
            storageViewModel.getImage(uID:self.uid, docID:cell.cellData.docID){(img) in
                self.diaryListViewModel.diaryList[indexPath.row].imageData = img
                cell.diaryTableViewCellImage.image = UIImage(data: img!)
            }
        }
        else{
            cell.diaryTableViewCellImage.isHidden = true
            cell.diaryTableViewCellImage.image = nil
        }
        
        return cell
    }
    ...
  • if let imageData = cell.cellData.imageData: 만약 이미지가 nil이 아니라면, 그러니까 현재 로딩 이미지 데이터가 있다면 storageVM을 통해 이미지를 로드하고 아니라면 이미지 뷰를 히든으로 만듭니다.
    • cell.diaryTableViewCellImage.image = UIImage(data: imageData): 이미지를 가져오는 건 굉장히 오래걸리는 일이므로 일단 로딩 이미지로 보여줍니다.
    • storageViewModel.getImage(uID:self.uid, docID:cell.cellData.docID){: 이미지를 가져오는 StorageVM의 메서드입니다.
      • self.diaryListViewModel.diaryList[indexPath.row].imageData = img: 현재 Diary의 이미지를 갱신합니다.
      • cell.diaryTableViewCellImage.image = UIImage(data: img!): UI를 원본이미지로 교체합니다.

제 나름대로 방법으로 해봤는데 혹시 더 빠르고 괜찮은 방법이 있다면 공유해주시면 감사하겠습니다

테스트

로그인 후 메인 화면에 이미지가 로드되는 상황입니다.

profile
개발자

0개의 댓글