Как декодировать TimeStamp из FireFase Firestore в Swift - PullRequest
0 голосов
/ 26 апреля 2019

Я хочу декодировать TimeStamp (как определено в FirebaseFirestore.Timestamp в swift) путем анализа ответа из базы данных firestore.

Приведенный ниже код для синтаксического анализа с сервера сообщает мне:

метод экземпляра 'decode (_: forKey :)' требует, чтобы 'Timestamp' соответствовал на «Декодируемый»

 created = try container.decode(FirebaseFirestore.Timestamp.self, forKey: .created)

также я не могу кодировать (сохранить локально или отправить на сервер) со следующей строкой:

try container.encode(created, forKey: .created)

компилятор говорит:

Невозможно преобразовать значение типа Timestamp в ожидаемый тип аргумента. 'Строка'

Полная копия-паста ниже

Кроме того, похоже, что метка времени - это словарь, а не целое число, потому что, когда я пытаюсь декодировать метку времени как целое число, я получаю ошибку:

Expected to decode Int but found a dictionary instead.

но мы все знаем, что [String: Any] (то есть словарь) невозможно декодировать.

import FirebaseFirestore

class SomeClassToParseFromFirestoresDatabase: Codable
{

  var created = FirebaseFirestore.Timestamp.init(date: Date())

  private enum CodingKeys: String, CodingKey
  {
    case created
  }

  func encode(to encoder: Encoder) throws
  {
    var container = encoder.container(keyedBy: CodingKeys.self)

    do
    {
      try container.encode(created, forKey: .created)
    }
    catch let error
    {
      print("error encoding to server or locally: \(error) ")
    }
  }


  required init(from decoder: Decoder) throws
  {
    let container = try decoder.container(keyedBy: CodingKeys.self)


    do
    {
      created = try container.decode(FirebaseFirestore.Timestamp.self, forKey: .created)
    }
    catch 
    {
      print("error getting 'created' from server: \(error) ")
    }
  }
}

Ниже приведен пример того, как проанализировать ответ из функции пожарного хранилища https.callable (которая просто возвращает JSON) - и использовать пользовательский класс ответа для анализа временной отметки в ответе (а также для сохранения временной отметки в классе). )

func getChatUsers( _ done: @escaping (ChatUsersResponse) -> ())
  {
    let response     = ChatUsersResponse()
    response.success = true

    let functions    = Functions.functions()

    functions.httpsCallable("getChatUsers").call
    { (result, error) in

      if let error = error as NSError?
      {
        response.success = false
        response.message = error.localizedDescription

        done(response)
      }
      else if let result = result,
        let data = result.data as? [String:Any],
        let users = data["users"]
      {
        do
        {
          let nsdata     = try JSONSerialization.data(withJSONObject: users, options: .prettyPrinted)
          **response.users = try JSONDecoder().decode([SomeClassToParseFromFirestoresDatabase].self, from:nsdata)**
          done(response)
        }
        catch let error
        {          
          response.success = false
          response.message = error.localizedDescription
          done(response)
          return
        }
      }
      else
      {
        response.success = false
        response.message = "Server responded with no error, but no users either"
        done(response)
      }
    }
  }

Ответы [ 2 ]

0 голосов
/ 01 мая 2019

Мне нужно было сделать 2 вещи.

Первым делом нужно было «установить» мою дату на стороне сервера с помощью функции toString () timeStamp - даже если по умолчанию она выглядит как строка,отметка времени не является строкой, и клиент анализирует пустой словарь.

Затем я смог взять эту строку и преобразовать ее в дату со следующим форматом даты

  let d = try container.decode(String.self, forKey: .created)
  //example: Fri Apr 26 2019 17:25:22
  let index = d.index(d.endIndex, offsetBy: -15) 
  let abc = d[..<index]

  let dateFormatter        = DateFormatter()
  dateFormatter.dateFormat = "EEE MMM dd yyyy HH:mm:ss"


  if let d = dateFormatter.date(from:String(abc))
  {
    created = d
  }
0 голосов
/ 27 апреля 2019

Немного неясно, что делает код в вопросе, но, может быть, если мы просто упростим процесс, это поможет.

Вот функция для записи метки времени Firestore в коллекцию «меток времени», каждый документ будет иметь уникальный идентификатор документа и дочернее поле «штемпеля»

func writeTimestampAction() {
    let now = Date()
    let stamp = Timestamp(date: now)

    let docRef = self.db.collection("timestamps").document()
    docRef.setData( [
        "stamp": stamp
    ])
}

и затем функция для чтения всех временных меток из этой коллекции и вывода их на консоль в формате гггг-мм-дд.

func readTimestampAction() {
    self.db.collection("timestamps").getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            for document in querySnapshot!.documents {
                if let stamp = document.get("stamp") {
                    let title = document.documentID
                    let ts = stamp as! Timestamp
                    let aDate = ts.dateValue()
                    let formatter = DateFormatter()
                    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ"
                    let formattedTimeZoneStr = formatter.string(from: aDate)
                    print(title, formattedTimeZoneStr)

                }
            }
        }
    }
}

Редактировать

Он является классом активности, которому можно передать снимок Firestore

class ActivityClass {
    var activity_name = ""
    var activity_date: Timestamp?

    convenience init(withDoc: QueryDocumentSnapshot) {
        self.init()
        if let stamp = withDoc.get("stamp") {
            self.activity_date = stamp as? Timestamp
        }
    }
}

и когда вы извлекаете данные из Firestore, просто сделайте это

for document in querySnapshot!.documents {
   let myActivity = ActivityClass(withDoc: document)
   //do something with myActivity
...