Я использую Firestore вместе со Swift.
У меня есть одноэлементный класс данных UserManager. Я вызываю это из своих разных ViewController, чтобы получить данные для заполнения моих табличных представлений. Я хочу, чтобы представления таблиц автоматически обновлялись при обновлении коллекций, поэтому мне нужно использовать SnapshotListener. Все работает нормально, но я не уверен, как отключиться от слушателя, когда Viewcontroller закрыт.
В одноэлементном классе у меня есть такие методы, как показано ниже. Метод дает список пользователей и будет вызываться из нескольких разных мест в моем приложении.
Я также хочу вернуть ссылку на слушателя, чтобы я мог отсоединиться от него, когда Viewcontroller закрыт. Но я не могу заставить его работать. Приведенное ниже решение дает ошибку компилятора.
Пытался посмотреть ссылку, например здесь https://firebase.google.com/docs/firestore/query-data/listen, но мне нужно заставить его работать, когда данные загружаются в одноэлементном классе, а не непосредственно в Viewcontroller. Какой путь сюда?
В UserManager:
func allUsers(completion:@escaping ([User], ListenerRegistration?)->Void) {
let listener = db.collection("users").addSnapshotListener { querySnapshot, error in
if let documents = querySnapshot?.documents {
var users = [User]()
for document in documents {
let user = User(snapshot: document)
users.append(user)
}
completion(users, listener)
}
}
}
В ViewController:
override func viewDidLoad() {
super.viewDidLoad()
UserManager.shared.allUsers(completion: { (users, listener) in
self.users = users
self.listener = listener
self.tableView.reloadData()
})
}
deinit {
self.listener.remove()
}





Я думаю, что getDocument вместо addSnapshotListener - это то, что вы ищете. Используя этот метод, слушатель автоматически отключается в конце запроса ... Это будет что-то похожее на
func allUsers(completion:@escaping ([User])->Void) {
db.collection("users").getDocument { querySnapshot, error in
if let documents = querySnapshot?.documents {
var users = [User]()
for document in documents {
let user = User(snapshot: document)
users.append(user)
}
completion(users)
}
} }
Спасибо! Но мне нужно использовать addSnapshotListener, поскольку я хочу, чтобы представления таблиц автоматически обновлялись при обновлении коллекций. Проблема, с которой я столкнулся, заключается в том, чтобы вернуть слушателя в viewcontroller, чтобы я мог позже удалить его. Я обновил свой вопрос, добавив более подробную информацию
Я угадать ошибка компилятора, которую вы видите, относится к тому факту, что вы используете listener в его собственном определяющем контексте.
Попробуйте это для разнообразия:
В UserManager:
func allUsers(completion:@escaping ([User])->Void) -> ListenerRegistration? {
return db.collection("users").addSnapshotListener { querySnapshot, error in
if let documents = querySnapshot?.documents {
var users = [User]()
for document in documents {
let user = User(snapshot: document)
users.append(user)
}
completion(users)
}
}
}
В ViewController:
override func viewDidLoad() {
super.viewDidLoad()
self.listener = UserManager.shared.allUsers(completion: { (users) in
self.users = users
self.tableView.reloadData()
})
}
deinit {
self.listener.remove()
}
Как раз то, что мне нужно, чтобы исправить ту же проблему, что и у меня. Какое-то время я думал, что, возможно, у меня есть Rouge viewController, который дублировался в моем стеке navigationController или что-то в этом роде. В моем приложении он воспроизводит короткий звуковой сигнал, когда слушатель обнаруживает изменения, поэтому было довольно очевидно, что что-то происходит с несколькими звуковыми сигналами одновременно, lol. БЛАГОДАРЮ ВАС!
Я застрял на типе "ListenerRegistration", так что это помогло. Это где-нибудь задокументировано?
Можете ли вы опубликовать ошибку вашего компилятора?