Примечание: после написания этого ответа я понял, что это было очень долго, но это большой вопрос, и есть много элементов для рассмотрения.
Мое первое предложение - изменить структуру, так как она слишком сложна длячто делается с данными. Кроме того, есть повторяющиеся данные, которые не нужны, поэтому их также следует изменить. Например, вот ваш узел профилей
"profiles": {
"FTgzbZ9uWBTkiZK9kqLZaAIhEDv1": {
"fcmToken": "fp09-Y9ZAkQ:APA91bFgGB1phr4B9gZScnz7ngpqTb5MchgWRFjHmLCVmWGMJVsyFx0rtrz7roxzpE_MmuSaMc4is-XIu7j718qjRVCSHY4PvbNjL1LZ-iytaeDP0oa8aJgE02wET3cXqKviIRMH",
"name": "Skander",
"phoneNumber": "+95644125503",
"uid": "FTgzbZ9uWBTkiZK9kqLZaAIhEDv1" <- remove this, not needed.
},
Как видите, у каждого дочернего узла есть ключ идентификатора пользователя. Но вы также сохраняете идентификатор пользователя как дочерний узел. Они являются ключом uid и всегда будут доступны, поэтому нет необходимости дублировать их, и дочерний узел должен быть удален.
На основе комментариев это гораздо лучшая структура
/users
FTgzbZ9uWBTkiZK9kqLZaAIhEDv1
"batteryStatus": 22,
"latitude": 40.9910537,
"longitude": 29.020425,
"timeStamp": 1556568633477,
"fcmToken": "fp09-Y9ZAkQ:APA91bFgGB1phr4B9gZScnz7ngpqTb5MchgWRFjHmLCVmWGMJVsyFx0rtrz7roxzpE_MmuSaMc4is-XIu7j718qjRVCSHY4PvbNjL1LZ-iytaeDP0oa8aJgE02wET3cXqKviIRMH",
"name": "Skander",
"phoneNumber": "+95644125503",
"conversationUid": "-L_w2yi8gh49GppDP3r5",
"friendStatus": "STATUS_ACCEPTED",
"notify": true,
"phoneNumber": "+915377588674",
изатем, чтобы отслеживать друзей пользователей, он становится следующим:
/userFriends
zzV6DQSXUyUkPHgENDbZ9EjXVBj2 //this user
FTgzbZ9uWBTkiZK9kqLZaAIhEDv1: true //their friend
IRoo0lbhaihioSSuFETngEEFEeoi: true //another friend
Чтобы загрузить друзей этих пользователей, мы читаем данные в / userFriends / this_users_id и затем перебираем дочерние узлы, загружая данные для отображения вtableView
Давайте начнем с объекта, который будет использоваться для хранения данных каждого друга, а затем массива, который будет использоваться в качестве источника данных tableView
class FriendClass {
var uid = ""
var name = ""
//var profilePic
//var batteryStatus
init(withSnapshot: DataSnapshot) {
self.uid = withSnapshot.key
self.name = withSnapshot.childSnapshot(forPath: "name").value as? String ?? "No Name"
}
}
var myFriendsDataSource = [FriendClass]()
Затем функции для чтенияПользовательский узел перебирает пользовательские uid друзей и читает данные каждого пользователя, заполняя объект FriendClass и сохраняя каждый в массиве. Обратите внимание, что self.ref указывает на мою базу данных.
func loadUsersFriends() {
let uid = "zzV6DQSXUyUkPHgENDbZ9EjXVBj2"
let myFriendsRef = self.ref.child("userFriends").child(uid)
myFriendsRef.observeSingleEvent(of: .value, with: { snapshot in
let uidArray = snapshot.children.allObjects as! [DataSnapshot]
for friendsUid in uidArray {
self.loadFriend(withUid: friendsUid.key)
}
})
}
func loadFriend(withUid: String) {
let thisUserRef = self.ref.child("users").child(withUid)
thisUserRef.observeSingleEvent(of: .value, with: { snapshot in
let aFriend = FriendClass(withSnapshot: snapshot)
self.myFriendsDataSource.append(aFriend)
})
}
Теперь, когда у нас есть код для чтения данных, вы также хотите следить за изменениями. Есть несколько вариантов, но вот два.
1) Я назову эту грубую силу.
Просто прикрепите наблюдателя .childChanged к узлу / users и, если что-то изменится, это изменилосьузел передается наблюдателю. Если ключ к этому узлу совпадает с ключом в массиве myFriendsDataSource, обновите этого пользователя в массиве. Если совпадения нет, игнорируйте его.
func watchForChangesInMyFriends() {
let usersRef = self.ref.child("users")
usersRef.observe(.childChanged, with: { snapshot in
let key = snapshot.key
if let friendIndex = self.myFriendsDataSource.firstIndex(where: { $0.uid == key} ) {
let friend = self.myFriendsDataSource[friendIndex]
print("found user \(friend.name), updating")
//friend(updateWithSnapshot: snapshot) //leave this for you to code
}
})
}
2) Выборочное наблюдение
Для этого мы просто присоединяем наблюдателя .childChanged к каждому узлу-другу - и это можно сделать в коде. пример сверху
func loadFriend(withUid: String) {
let thisUserRef = self.ref.child("users").child(withUid)
thisUserRef.observeSingleEvent(of: .value, with: { snapshot in
let aFriend = FriendClass(withSnapshot: snapshot)
self.myFriendsDataSource.append(aFriend)
//add an observer to this friends node here.
})
}
И последнее: я не обращался к этому
"friendStatus": "STATUS_ACCEPTED",
Я бы подумал, что только друзья, которых вы приняли, есть в списке друзей, поэтому использование немногоне понятно. Однако, если вы хотите использовать его, вы можете сделать это
/userFriends
zzV6DQSXUyUkPHgENDbZ9EjXVBj2 //this user
FTgzbZ9uWBTkiZK9kqLZaAIhEDv1: "STATUS_ACCEPTED"
IRoo0lbhaihioSSuFETngEEFEeoi: "STATUS_DECLINED"
, а затем, когда вам захочется загрузить друзей, игнорируйте те, которые отклонены.
Если вы ДОЛЖНЫ сохранитьВаша текущая структура (которую я НЕ РЕКОМЕНДУЮ), методы в этом ответе будут работать и для этой структуры, однако, это будет намного больше кода, и вы будете перемещаться по большому количеству ненужных дополнительных данных, поэтому FirebaseСчет будет выше.