Удаление значения из локального словаря, когда firebase потомок удалял swift - PullRequest
0 голосов
/ 06 января 2020

Здравствуйте, я учусь тому, как правильно использовать базу данных Firebase в реальном времени. Я создаю приложение, в котором пользователь может менять свое рабочее место (базу). В моем профиле настройки контроллера пользователь выбирает свою базу через pickerView. База данных в реальном времени обновляется должным образом. У меня есть список всех пользователей и отдельный список для каждой базы. Где застрял на главном контроллере вида. У меня есть представление коллекции, в котором отображается список пользователей моего местоположения. Моя цель - увидеть, кто придет в мое местоположение или покинет мое местоположение. У меня есть 2 функции, одна из которых доставляет мои собственные данные пользователя. которые определяют текущую базу, которую я хочу показать

func fetchCurrentUser() {

        if currentUser == nil {
            common.errorAlert("Could not retrieve user details.")
            return
        }

        guard let userID = Auth.auth().currentUser?.uid else { return }

        ref.child(userID).observeSingleEvent(of: DataEventType.value) { (snapshot) in
            if !snapshot.exists() { return }
            let userDetailsData = snapshot.value as? NSDictionary
            self.id = userDetailsData?["id"] as? String ?? ""
            self.myBase = userDetailsData?["base"] as? String ?? ""
            self.indexBasePicker = userDetailsData?["baseIndex"] as? Int ?? 0
            self.headerPosition(self.indexBasePicker)
            if self.myBase != "" {
                self.fetchAllUsers()
            }
        }
    }

Вторые пользователи fetchall в моем местоположении:

func fetchAllUsers() {

        ref.child(myBase).observe(.childAdded, with: { (snapshot) in

            if let dictionary = snapshot.value as? [String: AnyObject] {
                let user = User(dictionary: dictionary)
                if  user.isAdmin == true {
                    self.usersArray.append(user)
                    self.reloadTeamCollectionView()
                }
            }
        })

        ref.child(myBase).observe(.childRemoved, with: { (snapshot) in

            if let dictionary = snapshot.value as? [String: AnyObject] {
                let user = User(dictionary: dictionary)

                for (index, userArray) in self.usersArray.enumerated() {
                    if userArray.id == user.id {
                        print(index)
                        self.usersArray.remove(at: index)
                        self.reloadTeamCollectionView()
                    }
                }
            }
        })

    }

проблема в том, что когда кто-то присоединяется к моему текущему местоположению, он добавляется в список, иногда несколько раз. и когда кто-то уходит через некоторое время, приложение выходит из строя с ошибкой индекса вне диапазона

, любая помощь будет чрезвычайно признательна

.
  "users" : {
    "BdxqjmhjM0O3nV8uK9iC3HICHy32" : {
      "availableStatus" : false,
      "base" : "FRA",
      "baseIndex" : 4,
      "committee" : "★",
      "email" : "",
      "fBMessenger" : "",
      "fileNumber" : "",
      "iMessage" : "",
      "id" : "BdxqjmhjM0O3nV8uK9iC3HICHy32",
      "isAdmin" : true,
      "isOnline" : true,
      "name" : "",
      "phone" : "",
      "position" : "",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/myunion-16f31.appspot.com/o/BdxqjmhjM0O3nV8uK9iC3HICHy32%2Fprofile_images%2FprofilePhoto?alt=media&token=e898f36f-7c3a-42a3-be4b-0a1b74cbd224",
      "whatsapp" : ""
    },
    "DKfHhnwMgbOfGg3IpqG9QxlayxV2" : {
      "availableStatus" : false,
      "base" : "FRA",
      "baseIndex" : 4,
      "committee" : "★ Officers",
      "email" : "",
      "fBMessenger" : "",
      "fileNumber" : "",
      "iMessage" : "",
      "id" : "DKfHhnwMgbOfGg3IpqG9QxlayxV2",
      "isAdmin" : true,
      "isOnline" : false,
      "name" : "",
      "phone" : "",
      "position" : "",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/myunion-16f31.appspot.com/o/DKfHhnwMgbOfGg3IpqG9QxlayxV2%2Fprofile_images%2FprofilePhoto?alt=media&token=204f4187-b508-405e-9835-bfdf5250019f",
      "whatsapp" : ""
    },
    "GMupdPogn7YUag855TnWJkuzVzo1" : {
      "availableStatus" : "Online",
      "base" : "FRA",
      "baseIndex" : 4,
      "committee" : "Eap",
      "email" : "lisa@lisa.com",
      "fBMessenger" : "",
      "fileNumber" : "u182874",
      "iMessage" : "",
      "id" : "GMupdPogn7YUag855TnWJkuzVzo1",
      "isAdmin" : true,
      "name" : "",
      "phone" : "",
      "position" : "",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/myunion-16f31.appspot.com/o/GMupdPogn7YUag855TnWJkuzVzo1%2Fprofile_images%2FprofilePhoto?alt=media&token=8b3ec821-adad-47a9-943f-2cd4af50e436",
      "whatsapp" : ""
    },
    "LS8plMZmlmSXsu9kVZxXRKsuPT13" : {
      "availableStatus" : true,
      "base" : "FRA",
      "baseIndex" : 4,
      "committee" : "Communication",
      "email" : ",
      "fBMessenger" : "",
      "fileNumber" : "",
      "iMessage" : "",
      "id" : "LS8plMZmlmSXsu9kVZxXRKsuPT13",
      "isAdmin" : true,
      "isOnline" : true,
      "name" : "",
      "phone" : "",
      "position" : "Chair",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/myunion-16f31.appspot.com/o/LS8plMZmlmSXsu9kVZxXRKsuPT13%2Fprofile_images%2FprofilePhoto?alt=media&token=10ec728b-db42-485a-849d-0e2bcc0b3ba3",
      "whatsapp" : "+33642056110"
    },
    "sqfl1FmeiiOuoq8dPePULYDEsnv2" : {
      "availableStatus" : true,
      "base" : "FRA",
      "baseIndex" : 4,
      "committee" : "",
      "email" : "nonadmin@test.com",
      "fBMessenger" : "",
      "fileNumber" : "u182222",
      "iMessage" : "",
      "id" : "sqfl1FmeiiOuoq8dPePULYDEsnv2",
      "isAdmin" : false,
      "isOnline" : false,
      "name" : "Nonadmin Test",
      "phone" : "",
      "position" : "",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/myunion-16f31.appspot.com/o/sqfl1FmeiiOuoq8dPePULYDEsnv2%2Fprofile_images%2FprofilePhoto?alt=media&token=d4cfa840-954e-41fa-8490-23a5cd49fa56",
      "whatsapp" : ""
    }
  },
  "usersOffline" : {
    "DKfHhnwMgbOfGg3IpqG9QxlayxV2" : {
      "base" : "FRA",
      "baseIndex" : 4,
      "committee" : "★ Officers",
      "email" : "merv",
      "fBMessenger" : "",
      "fileNumber" : "",
      "iMessage" : "",
      "id" : "",
      "isAdmin" : true,
      "isOnline" : false,
      "name" : "Merv",
      "phone" : "",
      "position" : "Vice President",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/myunion-16f31.appspot.com/o/DKfHhnwMgbOfGg3IpqG9QxlayxV2%2Fprofile_images%2FprofilePhoto?alt=media&token=204f4187-b508-405e-9835-bfdf5250019f",
      "whatsapp" : ""
    },
    "sqfl1FmeiiOuoq8dPePULYDEsnv2" : {
      "base" : "FRA",
      "baseIndex" : 4,
      "committee" : "",
      "email" : "nonadmin@test.com",
      "fBMessenger" : "",
      "fileNumber" : "u182222",
      "iMessage" : "",
      "id" : "sqfl1FmeiiOuoq8dPePULYDEsnv2",
      "isAdmin" : false,
      "isOnline" : false,
      "name" : "Nonadmin Test",
      "phone" : "",
      "position" : "",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/myunion-16f31.appspot.com/o/sqfl1FmeiiOuoq8dPePULYDEsnv2%2Fprofile_images%2FprofilePhoto?alt=media&token=d4cfa840-954e-41fa-8490-23a5cd49fa56",
      "whatsapp" : ""
    }
  },
  "usersOnline" : {
    "BdxqjmhjM0O3nV8uK9iC3HICHy32" : {
      "base" : "FRA",
      "baseIndex" : 4,
      "committee" : "★ Officers",
      "email" : "",
      "fBMessenger" : "",
      "fileNumber" : "",
      "iMessage" : "",
      "id" : "",
      "isAdmin" : true,
      "isOnline" : true,
      "name" : "",
      "phone" : "",
      "position" : "",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/myunion-16f31.appspot.com/o/BdxqjmhjM0O3nV8uK9iC3HICHy32%2Fprofile_images%2FprofilePhoto?alt=media&token=e898f36f-7c3a-42a3-be4b-0a1b74cbd224",
      "whatsapp" : "+31620422185"
    },
    "LS8plMZmlmSXsu9kVZxXRKsuPT13" : {
      "base" : "FRA",
      "baseIndex" : 4,
      "committee" : "Communication",
      "email" : "",
      "fBMessenger" : "",
      "fileNumber" : "",
      "iMessage" : "",
      "id" : "LS8plMZmlmSXsu9kVZxXRKsuPT13",
      "isAdmin" : true,
      "isOnline" : true,
      "name" : "",
      "phone" : "",
      "position" : "Chair",
      "profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/myunion-16f31.appspot.com/o/LS8plMZmlmSXsu9kVZxXRKsuPT13%2Fprofile_images%2FprofilePhoto?alt=media&token=10ec728b-db42-485a-849d-0e2bcc0b3ba3",
      "whatsapp" : "+33642056110"
    }
  }
}

У меня есть 2 ссылки

  let ref = Database.database().reference(withPath: "users")
    let refOnline = Database.database().reference(withPath: "usersOnline")
    let refOffline = Database.database().reference(withPath: "usersOffline")

это как обновляется профиль пользователя при нажатии кнопки сохранения

   func updateDatasIsOnline(online: Bool) {

           if currentUser == nil {
         //      common.errorAlert("Error could not read user details")
               print("Error could not read user details")
               return
           }


           let filename = "profilePhoto"


           Storage.storage().reference().child(self.currentUser?.uid ?? "").child("profile_images").child(filename).downloadURL { (url, error) in
               guard let downloadURL = url else {
                   common.errorAlert(error?.legibleLocalizedDescription ?? "")
                   return }

               let userValues = [
                   "id": self.currentUser?.uid ?? "",
                   "name": self.nameTextField.text ?? "",
                   "committee": self.selectedCommitteeName,
                   "position": self.positionTextField.text ?? "",
                   "base": self.myBase,
                   "baseIndex": self.basePickerPosition,
                   "isAdmin": self.isAdmin,
                   "isOnline": online,
                   "email": self.emailTextField.text ?? "",
                   "phone": self.reformatPhoneNumberForDataBase(self.phoneNumberTextField.text ?? ""),
                   "iMessage": self.iMessageTextField.text ?? "",
                   "whatsapp": self.reformatPhoneNumberForDataBase(self.whatsappTextField.text ?? ""),
                   "fBMessenger": self.fBMessengerTextField.text ?? "",
                   "profileImageUrl": downloadURL.absoluteString,
                   "fileNumber": self.fileNbr
                   ] as [String : Any]

            if online == true {
                 self.ref.child(self.currentUser?.uid ?? "").updateChildValues(["isOnline" : true])
                self.refOnline.child(self.currentUser?.uid ?? "").setValue(userValues)
                self.refOffline.child(self.currentUser?.uid ?? "").removeValue()
            } else {
                self.ref.child(self.currentUser?.uid ?? "").updateChildValues(["isOnline" : false])
                self.refOffline.child(self.currentUser?.uid ?? "").setValue(userValues)
                self.refOnline.child(self.currentUser?.uid ?? "").removeValue()
            }
        }

       }

1 Ответ

0 голосов
/ 08 января 2020

Кажется, что вы перемещаете много данных в базе данных. Это может дорого обойтись, но потребляет много трафика. Другими словами, в текущем коде, если статус пользователя изменяется с онлайн на автономный, ваш код в настоящее время удаляет все пользовательские данные с одного узла и перезаписывает их на другой, когда все, что действительно необходимо, - это переключить сетевой флаг от да до нет.

Я представляю другой вариант, который может помочь в долгосрочной перспективе, и, хотя он не устраняет неполадки в существующем коде, он может быть лучшим вариантом.

Идея состоит в том, чтобы сохранить пользовательские данные в одном месте и просто изменить дочерние узлы, чтобы отразить другой статус; другая база, онлайн / офлайн и т. д. c.

. Для этого, если свойство (дочерний узел) попадает в критерии запроса, вы будете уведомлены. Если это не соответствует критериям, вы будете уведомлены.

Вот как будет выглядеть предложенный пользовательский узел. Обратите внимание, что нет никаких оффлайн или онлайн узлов, только пользовательский узел

users
   uid_0 //a users uid
      base: "FRA"
      name: "Frank"
      online: "no"
   uid_1
      base: "ENG"
      name: "Henry"
      online: "yes"
   uid_0 
      base: "FRA"
      name: "Leroy"
      online: "yes"

Из этого вы знаете, что Фрэнк находится во Франции, но не в сети, Генри находится в Англии и онлайн, а Леруа также во Франции и онлайн .

Вот мой класс пользователей и массив для их хранения в

class UserAndBaseClass {
    var uid = ""
    var name = ""
    var base = ""
    var online = ""

    init(withSnap: DataSnapshot) {
        self.uid = withSnap.key
        self.name = withSnap.childSnapshot(forPath: "name").value as? String ?? "No Name"
        self.base = withSnap.childSnapshot(forPath: "base").value as? String ?? "No Base"
        self.online = withSnap.childSnapshot(forPath: "online").value as? String ?? "Offline"
    }
}

var usersArray = [UserAndBaseClass]()

. В первом разделе кода AddedQuery запрашивает всех пользователей, принадлежащих к базе текущих пользователей, FRA. и сохраняет их в массиве. Это оставляет наблюдателя на узле пользователей, поэтому, если какая-либо база пользователей становится FRA, она попадает в параметры этого запроса и добавляется к запросу. (следовательно, вызывая событие .childAdded)

Второй раздел, удаленный с помощью Query, устанавливает запрос для всех пользователей, которые соответствуют запросу, и событие запускается, если база становится чем-то отличным от FRA - например, дочерний элемент удалены из параметров запроса, и событие .childRemoved сработало.

Обратите внимание, что мы вообще не используем .childChanged, поскольку первые два запроса покрывают его.

func observeUserBases() {

    let currentUserBase = "FRA"

    //get everyone in the current users base, FRA. This also fires if a user changes to this base
    let usersRef = self.ref.child("users")
    let addedQuery = usersRef.queryOrdered(byChild: "base").queryEqual(toValue: currentUserBase)
    addedQuery.observe(.childAdded, with: { snapshot in
        let user = UserAndBaseClass(withSnap: snapshot)
        self.usersArray.append(user)
        print("\(user.name) has been added to your base")
    })

    //this will catch any users that were removed as well as users who left your base
    let removedQuery = usersRef.queryOrdered(byChild: "base").queryEqual(toValue: "FRA")
    removedQuery.observe(.childRemoved, with: { snapshot in
        let keyToRemove = snapshot.key
        if let index = self.usersArray.firstIndex(where: { $0.uid == keyToRemove } ) {
            let name = self.usersArray[index].name
            print("\(name) has left your base")
            self.usersArray.remove(at: index)
        }
    })


    let onlineQuery = usersRef.queryOrdered(byChild: "online").queryEqual(toValue: "yes")
    onlineQuery.observe(.childAdded, with: { snapshot in
        let keyOfChanged = snapshot.key
        let base = snapshot.childSnapshot(forPath: "base").value as? String ?? "No Base"

        if base == currentUserBase {
            if let index = self.usersArray.firstIndex(where: { $0.uid == keyOfChanged } ) {
                let name = self.usersArray[index].name
                print("\(name) is now online")
                self.usersArray[index].online = "yes"
            }
        }
    })

    let offlineQuery = usersRef.queryOrdered(byChild: "online").queryEqual(toValue: "no")
    offlineQuery.observe(.childAdded, with: { snapshot in
        let keyOfChanged = snapshot.key
        let base = snapshot.childSnapshot(forPath: "base").value as? String ?? "No Base"

        if base == currentUserBase {
            if let index = self.usersArray.firstIndex(where: { $0.uid == keyOfChanged } ) {
                let name = self.usersArray[index].name
                print("\(name) has gone offline")
                self.usersArray[index].online = "no"
            }
        }
    })
}

Последний два раздела, онлайн и оффлайн запрос, структурированы немного по-разному; каждый ищет узлы, которые соответствуют параметрам запроса. Один ищет узлы, которые соответствуют онлайн = да, автономный соответствует узлам, которые соответствуют автономному = нет. Отмечая, что код фактически отслеживает ВСЕХ пользователей, но игнорирует пользователей, которых нет в базе текущих пользователей.

Альтернативой этому является добавление отдельных наблюдателей для каждого пользователя / онлайн-узла, который является частью этой базы. Это можно сделать в замыкании addQuery и добавить наблюдателя для каждого узла пользователей по мере его добавления, а затем в removeQuery удалить наблюдателя, когда пользователь покидает базу. Я оставлю это в упражнении.

Надеюсь, это поможет, предложив альтернативу перемещению всех этих данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...