Firebase 라이브러리처럼 만들어보기

Groot·2022년 10월 10일
0

TIL

목록 보기
76/148
post-thumbnail

TIL

🌱 난 오늘 무엇을 공부했을까?

📌 Firebase Real-Time Database Tutorial for iOS 참고해서 간단하게 라이브러리처럼 만들어보기

📍 Real-Time Database VS Firestore

  • Real-Time Database
    - 강점

        1. 사용자가 온라인 또는 오프라인 상태일 때 모니터링하기 위해 사용자 존재를 지원합니다.
        2. 대기 시간이 매우 짧습니다.
        3. 대역폭 및 스토리지에 대한 요금은 부과되지만 데이터베이스에서 수행되는 작업에 대해서는 요금이 부과되지 않습니다.
        4. 200k 동시 연결로 확장됩니다.

    - 약점 
    
        1. 다중 지역 지원이 없습니다. 데이터는 지역 구성에서만 사용할 수 있습니다.
        2. 제한된 정렬 및 필터링 기능이 있습니다.
  • Firestore

    • 강점

      1. 실시간 데이터베이스보다 구조화되어 데이터에 대해 더 복잡한 쿼리를 수행할 수 있습니다.
      2. 실시간 데이터베이스보다 더 잘 확장되도록 설계되었습니다. 확장 제한은 현재 약 100만 개의 동시 연결입니다.
      3. 개별 지역에 데이터를 저장하는 여러 데이터 센터가 있으며 다중 지역 구성을 지원할 수 있습니다.
      4. 주로 데이터베이스에서 수행되는 작업에 대해 요금을 부과하며 더 낮은 요율로 대역폭 및 스토리지를 청구합니다.
    • 약점

      1. 문서가 초당 한 번보다 빠른 속도로 업데이트되는 것을 허용하지 않습니다.
      2. 사용자의 위상을 지원하지 않습니다.

📍 Firebase 라이브러리처럼 만들어보기

import Firebase
import FirebaseDatabase

enum RepositoryError: Error {
    case encoding
    case decoding
    case JSONSerialization
    case network
    case dataSnapshot
}

class FirebaseRepository<T: Codable> {
    typealias Entity = T
    
    private let reference: DatabaseReference
    private let rootChildID: String
    
    init(rootChildID: String) {
        self.rootChildID = rootChildID
        reference = Database.database().reference()
    }
    
    func setValue(childId: String, model: Entity) throws {
        guard let encodedData = try? JSONEncoder().encode(model)
        else { throw RepositoryError.encoding }
        
        guard let jsonData = try? JSONSerialization.jsonObject(with: encodedData)
        else { throw RepositoryError.JSONSerialization}
        
        reference.child(rootChildID).child(childId).setValue(jsonData)
    }
    
    func readAllValue(completionHandler: @escaping((Result<[Entity], RepositoryError>) -> Void)) {
        reference.child(rootChildID).observeSingleEvent(of: .value, with: { [weak self] snapshot in
            guard let self = self
            else { return }
            
            let dictionary = self.convertDataSnapshot(snapshot)
            let jsondata = self.convertJSONSerialization(with: dictionary)
            let model = self.decode(with: jsondata)
            
            completionHandler(model)
        })
    }
    
    func deleteValue(childId: String) {
        reference.child(rootChildID).child(childId).removeValue()
    }
    
    private func decode(with data:
                        Result<Data, RepositoryError>) -> Result<[Entity], RepositoryError> {
        switch data {
        case .success(let jsonData):
            guard let decodedData = try? JSONDecoder().decode([Entity].self, from: jsonData)
            else { return .failure(.decoding)}
            
            return .success(decodedData)
        case.failure(let error):
            return .failure(error)
        }
    }
    
    private func convertDataSnapshot(_ snapshot:
                                     DataSnapshot) -> Result<[String : Any], RepositoryError> {
        guard let dictionary = snapshot.value as? [String: Any]
        else { return .failure(.dataSnapshot) }
        
        return .success(dictionary)
    }
    
    private func convertJSONSerialization(with dictionary:
                                          Result<[String : Any], RepositoryError>)
    -> Result<Data, RepositoryError>
    {
        switch dictionary {
        case .success(let data):
            guard let jsonData = try? JSONSerialization.data(withJSONObject: data)
            else { return .failure(.JSONSerialization)}
            
            return .success(jsonData)
        case .failure(let error):
            return .failure(error)
        }
    }
}

📍 후기

  • 실제로 배포하고있는 라이브러리에서 에러처리를 어떻게 하고있는지 찾아봐야겠다.. 그 동안 에러처리에 신경쓰지 않고 코드를 만들어서 "어디까지 에러전달을 해야하고, 어디서 에러처리를 할 것인가"의 문제가 어렵게 만들었다... 특히 네트워크나 데이터 관련 부분에선 에러처리에 신경을 썼어야 했는데 그걸 그냥 nil처리로 넘겼음에 반성한다.. 진짜 멀었다..

Firebase Real-Time Database Tutorial for iOS

profile
I Am Groot

0개의 댓글