24.09.02 Today I Learned

2024. 9. 2. 18:10

FireBase 공부하기!

 

전체코드를 보면 이러한 형태인데 지인의 코드를 빌려 공부를 하기로 했다.

import Foundation
import FirebaseFirestore

class HistoryRepository {
    private let db = Firestore.firestore()
    static let shared = HistoryRepository() 
    
    // 사용내역 조회
    func fetchHistoryInfos(for email: String) {
        db.collection("history").whereField("email", isEqualTo: email).getDocuments { (querySnapshot, error) in
            if let error = error {
                print("Error getting documents: \(error)")
            } else {
                var historyInfos: [HistoryStruct] = []
                for document in querySnapshot!.documents {
                    if let historyInfo = HistoryStruct(dictionary: document.data()) {
                        historyInfos.append(historyInfo)
                    }
                }
                History.shared.updateHistories(with: historyInfos)
            }
        }
    }

    // 사용내역 추가
    func addHistoryInfo(_ historyInfo: HistoryStruct) {
        db.collection("history").addDocument(data: historyInfo.dictionary) { error in
            if let error = error {
                print("Error adding document: \(error)")
                NotificationCenter.default.post(name: .didAddHistoryInfo, object: nil, userInfo: ["success": false])
            } else {
                NotificationCenter.default.post(name: .didAddHistoryInfo, object: nil, userInfo: ["success": true])
            }
        }
    }
}

extension Notification.Name {
    static let didAddHistoryInfo = Notification.Name("didAddHistoryInfo")
}

이제 코드를 뜯어보면서 공부를 시작해보자!


private let db = Firestore.firestore()

우선 Firestore 데이터베이스에 접근하기 위해 Firsestore 인스턴스를 생성함!

이 'db'를 통해 Firestore의 컬렉션과 문서에 접근할 수 있게됨.

static let shared = HistoryRepository()

이 클래스에서는 싱글톤 패턴을 적용하여, 앱 내에서 이 클래스의 인스턴스가 단 하나만 존재하도록 보장함! 이를 통해 어디서든 이 인스턴스를 사용하여 데이터에 접근할 수 있게 했음.

// 사용내역 조회
    func fetchHistoryInfos(for email: String) {
    
    	// db에 있는 history라는 collection을 참조, Firestore 쿼리를 사용하여 email 필드가 제공된 email 값과 동일한 모든 문서를 가져오겠다는 의미.
        // getDocuments는 Firestore에서 쿼리를 실행하고 해당 문서들을 비동기적으로 가져오는 메서드, 쿼리 결과를 querySnapshot으로 반환하거나 쿼리중 발생한 오류를 error로 반환
        db.collection("history").whereField("email", isEqualTo: email).getDocuments { (querySnapshot, error) in
        
        	// 쿼리 실행중 에러가 발생했는지 확인하는 코드
            if let error = error {
                print("Error getting documents: \(error)")
            } else { //발생하지 않았다면 실행하는 코드
            
            	// 사용내역 정보를 저장할 빈 배열 historyInfos를 생성, HistoryStruct타입의 데이터를 저장함
                var historyInfos: [HistoryStruct] = []
                
                // querySnapShot은 쿼리 결과를 포함하고 있는 객체, querySnapshot!.documents는 쿼리 결과로 반환된 문서들의 배열임.
                // 이 배열에서 각 문서를 순회(for)하면서 처리함
                // 왜 !를 사용하여 강제언래핑을 했을까?, querySnapshot이 nil이 아님을 확신해서인가? 
				// 안전성을 생각하면 옵셔널 바인딩(if let, guard let을 사용해보는거도 생각해봐야겠다)
                for document in querySnapshot!.documents { 
                
                // 각 document의 데이터를 document.data()를 통해 딕셔너리로 가져옴. 
                // 그 딕셔너리를 사용하여 HistoryStruct의 초기화 메서드를 호출해 HistoryStruct 객체를 생성
                // 이 과정에서 데이터가 올바르게 변환이 됐다면(if let), 생성된 historyInfo를 historyInfos배열에 추가함
                    if let historyInfo = HistoryStruct(dictionary: document.data()) {
                        historyInfos.append(historyInfo)
                    }
                }
                // 모든 문서를 처리한 후, historyInfos 배열에 사용 내역 데이터가 쌓이게 됨.
                // 그 후 History.shared.updateHistories(with: historyInfos)를 호출하여 History라는 싱글톤 클래스의 데이터를 새로가져온 historyInfos로 갱신
                History.shared.updateHistories(with: historyInfos)
            }
        }
    }

쿼리란?

: 데이터베이스에서 원하는 데이터를 검색하거나 조작하기 위해 작성하는 요청 또는 명령임. 쉽게 말하자면 "내가 찾고자 하는 데이터가 무엇인지"를 데이터 베이스에 요청하는 방법임.

 

쿼리를 통해 데이터베이스에 있는 데이터를 읽어오거나, 특정 조건에 맞는 데이터를 필터링하고, 새로운 데이터를 추가하거나, 기존 데이터를 수정 및 삭제할 수 있음.

 

예시 코드

db.collection("users").whereField("email", isEqualTo: "example@example.com"). getDocuments { (querySnapShot, error) in
 // 결과 처리
}

예를 들어, 이메일이 example@example.com 인 사용자의 데이터를 가져오려면 위 코드처럼 작성하면 됨.

이 쿼리는 users 컬렉션에서, email필드가 example@example.com 과 일치하는 문서를 검색하라는 요청임.

 

다음 사용내역 추가를 보면, addHistoryInfo라는 메서드를 정의하여, 사용 내역 정보를 Firestore에 추가하는 기능을 구현하고 있음.

추가로 Firestore에 데이터 추가 작업 성공여부에 따라 알림(Notification)을 발생시켜 앱 내 다른 부분에서 해당 이벤트를 처리할 수 있도록 했음.

 

요약하자면,

1. Firestore에서 history 컬렉션에 접근하여 주어진 이메일과 일치하는 문서를 찾음.

2. 찾은 문서를 반복문으로 순회하고, 각 문서를 HistoryStruct로 변환하여 배열에 추가함.

3. 이 배열을 History 싱글톤에 전달하여 앱 내에서 사용 내역 데이터를 갱신함.

 

// 사용내역 추가
	
    // 하나의 파라미터 'historyInfo'를 받아서 처리하는 함수 
    // historyInfo는 HistroyStruct 타입의 데이터로, 사용 내역 정보를 담고있는 구조체
    func addHistoryInfo(_ historyInfo: HistoryStruct) { // 목적 : historyInfo 데이터를 Firestore데이터 베이스의 'history'컬렉션에 추가하는 것
        
        // Firestore 데이터 베이스의 history 라는 컬렉션을 참조하고 historyInfo 데이터를 Firestore에 새로운 문서로 추가함
        // 'data'파라미터로 전달되는 historyInfo.dictionary는 'HistoryStruct'의 데이터를 'String: Any'타입의 딕셔너리로 변환한 것 -> Firestore는 딕셔너리 형태의 데이터를 문서로 저장함
        // Firestore에서 데이터를 추가하는 작업은 비동기적으로 이루어지며, 완료되면 클로저를 통해 결과를 전달함.
        db.collection("history").addDocument(data: historyInfo.dictionary) { error in
        
        	// 오류가 발생했는지 안했는지 확인하는 구문
            if let error = error {
                print("Error adding document: \(error)") // 오류가 발생했을 때 오류 내용을 출력, success: false
                NotificationCenter.default.post(name: .didAddHistoryInfo, object: nil, userInfo: ["success": false])
            } else { // 오류가 발생하지 않았을 때,동일한 알림을 success: true를 담아 발생
                NotificationCenter.default.post(name: .didAddHistoryInfo, object: nil, userInfo: ["success": true])
            }
        }
    }
}

// Notification.Name의 확장을 통해 'didAddHistoryInfo'라는 커스텀 알림 이름을 정의함
// Notofication.Name("didAddHistoryInfo")는 알림의 고유한 식별자 역할을 함. 이 식별자를 통해 다른 클래스나 객체에서 이 알림을 구독하여 이벤트를 처리할 수 있음
extension Notification.Name {
    static let didAddHistoryInfo = Notification.Name("didAddHistoryInfo")
}

요약하자면,

1. 함수가 호출되면 historyInfo 데이터를 Firestore의 'history'컬렉션에 새로운 문서로 추가함.

2. Firestore에 데이터를 추가하는 작업이 완료된 후, 오류가 발생했는지의 여부를 파악함.

  • 오류가 발생한 경우, 오류 내용을 출력하고, 실패했다는 알림을 발생시킴
  • 오류가 없을 경우, 성공했다는 알림을 발생시킴

3. 알림(Notification)은 'NotificationCenter'를 통해 발생하며, 앱의 다른 부분에서도 이 알림을 구독하고 해당 이벤트에 대한 처리를 할 수 있음.

 

 

'Today I Learned > 2024' 카테고리의 다른 글

24.09.05 Today I Learned  (0) 2024.09.05
2024.09.03 Today I Learned  (1) 2024.09.03
24.08.26 Today I Learned  (0) 2024.08.26
24.08.23 Today I Learned  (0) 2024.08.25
24.08.20 Today I Learned  (0) 2024.08.20

BELATED ARTICLES

more