# #swift #firebase #google-cloud-firestore
Вопрос:
Мое приложение настроено с несколькими классами ___API, которые содержат код firebase для чтения и записи в мою базу данных firestore. Недавно я обнаружил полезность прослушивателей(.addSnapshotListener) для обновлений в реальном времени, где ранее мой проект состоял из одноразовых выборок (.getDocuments). До сих пор я нахожу их чрезвычайно полезными, однако управлять ими сложнее, потому что я должен удалять слушателя при переходе между представлениями.
В настоящее время я передаю объекты «ListenerRegistration» через мои завершения, мне нравится этот подход, однако я не могу ссылаться на слушателя, когда завершение вложено внутри слушателя. Мое текущее решение состоит в том, чтобы создать переменную для QuerySnapshot и использовать .asyncAfter, но, конечно, есть более элегантный способ получить доступ к слушателям в отдельных классах для легкого удаления без .asyncAfter:
static func fetchHosts(venID: String, completion: @escaping([UserModel], ListenerRegistration) -> Void){
var hostObj = [UserModel]()
var snapshot : QuerySnapshot? = nil
let listener = PRIV_VENUES_COLLECTION.document(venID).collection("Hosts").addSnapshotListener { _snapshot, e in
snapshot = _snapshot
///USUALLY THE CODE WITHIN THE ASYNC IS HERE,
///BUT completion(hostObj, listener) THROWS ERROR: (declaration before initialization)
}
DispatchQueue.main.asyncAfter(deadline: .now() 0.5) {
if let snap = snapshot{
snap.documents.forEach { doc in
let dic = doc.data()
let dateTimestamp = dic[DatabaseUserField.dateCreated] as? Timestamp
guard let date = dateTimestamp?.dateValue() else {print("NO Date")
return}
let userID = doc.documentID
ProfileAPI.fetchUserInfonDate(userID: userID, dateCreated: date) { aHost in
hostObj.append(aHost)
if hostObj.count == snap.documents.count{
let sort = hostObj.sorted(by: { $0.dateString! > $1.dateString! })
completion(sort, listener)
}
}
}
}else{
print("snapshot is nil")
}
}
}
Вот как я на самом деле использую «ListenerRegistration» в своем сетевом классе. В ViewController viewDidAppear я вызываю «выборку» и «отклонение» в viewDidDisappear
class HostNetworking{
var hostVC: HostViewController!
var venueData : VenueModel!
var hostListener : ListenerRegistration?
init(hostVC: HostViewController, venueData: VenueModel){
self.hostVC = hostVC
self.venueData = venueData
}
func fetchHosts(){
guard let venID = venueData.venID else {print("NO VENID")
return}
HostAPI.fetchHosts(venID: venID) { hostData, listener in
self.hostVC.hostObject = []
self.hostVC.hostObject = hostData
self.hostListener = listener
}
}
func dismissHostListener(){
guard let listener = self.hostListener else {print("NO HOST LISTNR")
return
}
print("Host Listener removed")
listener.remove()
}
Ответ №1:
Решение, которое я придумал, состояло в том, чтобы создать статические переменные в верхней части моего класса API, чтобы я мог просто задавать их слушателям при вызове выборки, так же как и функции, переменные легко доступны. Я могу эффективно удалять слушателей из любого места. Я все еще открыт для других решений, но это работает гладко.
class HostAPI{
static var guestListener : ListenerRegistration!
//MARK: - Fetch a venues guests
static func fetchGuests(venID: String, completion: @escaping([UserModel]) -> Void){
var guestObj = [UserModel]()
guestListener = PRIV_VENUES_COLLECTION.document(venID).collection("Guests").addSnapshotListener { snapshot, e in
if snapshot != nil{
snapshot!.documents.forEach({ doc in
let userID = doc.documentID
let dic = doc.data()
let timeStamp = dic[DatabaseUserField.dateCreated] as? Timestamp
guard let date = timeStamp?.dateValue() else {print("NO Date")
return}
ProfileAPI.fetchUserInfonDate(userID: userID, dateCreated: date) { user in
guestObj.append(user)
if guestObj.count == snapshot!.documents.count{
let sort = guestObj.sorted(by: { $0.dateString! > $1.dateString! })
completion(sort)
}
}
})
}else{
print("nil - guests")
}
}
}
}
Это код в сетевом классе:
class HostNetworking{
var hostVC: HostViewController!
var venueData : VenueModel!
var guestListener : ListenerRegistration!
init(hostVC: HostViewController, venueData: VenueModel){
self.hostVC = hostVC
self.venueData = venueData
}
//MARK: - Guests
func fetchGuests(){
guard let venID = venueData.venID else {print("NO VENID")
return}
HostAPI.fetchGuests(venID: venID) { guestData in
self.hostVC.guestsObject = []
self.hostVC.guestsObject = guestData
self.guestListener = HostAPI.guestListener
}
}
func dismissGuestListener(){
guard let listener = self.guestListener else {print("NO GUEST LISTNR")
return
}
print("Guest Listener removed")
listener.remove()
}
}