[SwiftUI Firebase] Real-time data updates in iOS App

Woozoo·2023년 4월 15일

[SwiftUI Firebase]

목록 보기
12/14
post-thumbnail

리스너를 알아봅시다

채팅같은 거 구현할 때 씀

UserManager에서 Listener를 추가해주는 메소드를 작성함


completion이 됐을 때 products를 @escaping으로 넘겨주고!

뷰모델에서 Listener추가해주는 메소드 다시 구성해줌!

그리고 view가 onAppear될 때 Listener를 추가해주면~
되는데 .onAppear가 딱 처음 등장할때만 리스너를 추가해줘야함!


변수하나 @State로 파서 처음 떴을 때만 listener가 추가되게 해줬다!

크~!!~!~!~!~!

데이터들 바로바로 적용되는 거 볼 수 있음!!


listener를 없애는 방법도 알아야겠죠
채팅방에 들어갔다가 나왔을 때는 더 이상 필요가 없을테니까!!



요런식으로~

func addListenerForAllUserFavoriteProducts(userId: String, completion: @escaping (_ products: [UserFavoriteProduct]) -> Void) {
    self.userFavoriteProductsListener = userFavoriteProductCollection(userId: userId).addSnapshotListener { querySnapshot, error in
        guard let documents = querySnapshot?.documents else {
            print("No documents")
            return
        }
        
        let products: [UserFavoriteProduct] = documents.compactMap({ try? $0.data(as: UserFavoriteProduct.self)})
        completion(products)
        
        querySnapshot?.documentChanges.forEach { diff in
            if (diff.type == .added) {
                print("New products: \(diff.document.data())")
            }
            if (diff.type == .modified) {
                print("Modified products: \(diff.document.data())")
            }
            if (diff.type == .removed) {
                print("Removed products: \(diff.document.data())")
            }
        }
        
    }
}

그래서 변한 걸 어떤건지에 대한 것들도
요렇게 if 문으로 나눌 수 있음



요 리스너를 publisher로 바꿔주는 것도 가능함!!

func addListenerForAllUserFavoriteProducts(userId: String) -> AnyPublisher<[UserFavoriteProduct], Error> {
    let publisher = PassthroughSubject<[UserFavoriteProduct], Error>()
    
    self.userFavoriteProductsListener = userFavoriteProductCollection(userId: userId).addSnapshotListener { querySnapshot, error in
        guard let documents = querySnapshot?.documents else {
            print("No documents")
            return
        }
        
        let products: [UserFavoriteProduct] = documents.compactMap({ try? $0.data(as: UserFavoriteProduct.self)})
        publisher.send(products)
    }
    return publisher.eraseToAnyPublisher()
}

earaseToAnyPublisher로 코드를 더 제네릭 하게 만들어줄 수도 있겠죠

실제로 교체해주면 뿜~!
combine으로 바꼈습니다~~


더 제네릭하게 바꿔볼까요

요렇게!


요렇게!!


그리고 아까 onAppear일 때 체크하려고 Bool값 만들어줬었잖음
그것도 바꿔봅시다

struct OnFirstAppearViewModifier: ViewModifier {
    
    @State private var didAppear: Bool = false
    let perform: (() -> Void)?
    
    func body(content: Content) -> some View {
        content
            .onAppear {
                if !didAppear {
                    perform?()
                    didAppear = true
                }
            }
    }
}

extension View {
    func onFirestAppear(perform: (() -> Void)?) -> some View {
        modifier(OnFirstAppearViewModifier(perform: perform))
    }
}

~
이게 ViewModifier의 힘이구나!!!

profile
우주형

0개의 댓글