Мне очень нравится писать код с Firebase. Это отличный бэкэнд с множеством различных инструментов. Но я упускаю простой способ проверить путь на наличие обновленных данных, когда включено постоянство. Я думаю, что это не редкость, потому что мне часто нужно, чтобы мое приложение действовало определенным образом в зависимости от последних данных сервера, которые нужно прочитать только один раз.

Обычно я использую observeSingleEventOfType, но это совершенно бесполезно, когда включена перисистенция, поскольку она никогда не будет получать последние данные сервера. Что я не понимаю почему. Должна быть добавлена ​​опция, позволяющая пропускать локальный кеш и искать только данные сервера.

Отключение постоянства решает эту проблему, и observeSingleEventOfType будет работать должным образом. Но это будет означать, что нужно заново реализовать все офлайн-возможности самостоятельно.

Первый сценарий:

 // chats contain meta information about the chat like last message and count of unread messages

 let chatRef = ref.child("chats").child(receiverId).child(chatId)
 chatRef.observeSingleEventOfType(.Value, withBlock: { (snapshot) -> Void in
     if !snapshot.exists() {
         print("snapshot does not exist")
         // the other side has deleted the chat
         // now delete all messages and member objects

         ref.child("messages").child(chatId).setValue(nil)
         ref.child("members").child(chatId).setValue(nil)
     } else {
         print("snapshot exists")
     }
 })

Я также пробовал chatRef.keepSynced(true) перед тем, как безуспешно наблюдать за событиями. Что в любом случае имеет смысл не во всех ситуациях:

Второй сценарий:

func removeOlderMessages() {
    let dateInThePast = NSDate().addDays(-30).timeIntervalSince1970 * 1000
    self.messagesRef.queryOrderedByChild("timestamp")
        .queryEndingAtValue(dateInThePast)
        .observeSingleEventOfType(.Value, withBlock: { (snapshot) -> Void in
            snapshot.ref.removeValue()
    })
}

Использование здесь keepSynced приведет к загрузке всех сообщений в messagesRef, что совершенно не нужно.

Так есть ли разумный обходной путь для этих двух сценариев? Любая помощь приветствуется.

12
MJQZ1347 26 Июн 2016 в 02:07
Та же проблема здесь stackoverflow.com/questions/37847265/…
 – 
DogCoffee
26 Июн 2016 в 02:56
Да, нам определенно нужно решение для этого. Мне любопытно, работает ли Firebase уже над функциями, позволяющими это сделать.
 – 
MJQZ1347
26 Июн 2016 в 21:34

1 ответ

Лучший ответ

Хорошо, я думаю, что нашел разумное решение для обоих сценариев:

Временное решение для первого сценария:

Используйте transactions. Они будут работать только тогда, когда вы в сети. Блок completition вернет последние данные сервера.

self.ref.child("chats").child(receiverId).child(chatId).runTransactionBlock({ (currentData) -> FIRTransactionResult in
    // Actually do nothing with the retrieved data and re-submit it.
    return FIRTransactionResult.successWithValue(currentData)
 }) { (error, success, snapshot) in

    if let error = error {
        print(error)
        return
    } else if !success || snapshot == nil {
       return
    }

    // snapshot contains the latest server data
    if !snapshot!.exists() {
       // the other side has deleted the chat
       // now delete all messages and member objects

       print("snapshot doesn't exist. deleting messages and members.")
       ref.child("messages").child(chatId).setValue(nil)
       ref.child("members").child(chatId).setValue(nil)     
    } else {
       print("snapshot exists. not deleting all messages and members.")
    }     
}

Обратной стороной является то, что получение данных займет значительно больше времени по сравнению с observeEventType или observeSingleEventOfType.

Временное решение для второго сценария:

Используйте observeEventType(.Value). Сначала он вернет кешированные, а затем последние данные сервера, если они доступны. Наблюдатель может быть удален через заданный интервал времени с помощью NSTimer.

В общем, эти обходные пути пока подходят, но функция пропуска локального кеша при использовании observeSingleEventOfType незаменима.

3
MJQZ1347 1 Июл 2016 в 16:32
Быстрый вопрос! При записи данных с использованием транзакции firebase, если подключение устройства к Интернету разрывается сразу после того, как была произведена запись, непосредственно перед отправкой ответа клиенту, отправит ли сервер ответ обратно, когда пользователь снова выйдет в сеть? Пример: Интернет прерывается непосредственно перед этой строкой }) { (error, success, snapshot) in. Другой сценарий: интернет отключается непосредственно перед if !snapshot!.exists(). Что здесь происходит? ваша функция не будет продолжать оценивать? Значит, ваше приложение останется в несогласованном состоянии, верно? Большое спасибо
 – 
bibscy
24 Июл 2017 в 00:59