alickbass/CodableFirebase

Timestamp Handling

yangricardo opened this issue · 5 comments

Hi am having this issue with CodableFirebase decoding
I have some Codable fields that represents Dates, already tried Date Swift and Firebase Timestamp, used the extension Timestamp: TimestampType {} in my code and still receiving this error:

Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "dataNascimento", intValue: nil)], debugDescription: "Expected to decode Double but found FIRTimestamp instead.", underlyingError: nil))

At some point of time this fields needs to be nil, and it works, but only when i fetch data from Firestore after update this field i get this error.

Uploading Captura de Tela 2018-10-28 às 15.39.35.png…

Hi! Thanks for posting your question! Could you please share the code with your struct that conforms to Codable?

Hi, thanks to answer!
An example is this:

class HabilitacaoBeneficiario: Codable {

var nomeCompleto : String?
var cpf : String?
var dataNascimento : Timestamp?
var grauParentesco : String?
var registroGeral : String?
var orgãoEmissor : String?
var dataExpedicao : Timestamp?
var estadoCivil : CivilStatus?
var numeroFilhos : Int?
var faixaRenda : Income?
var ppe : Bool?
var residenteBrasil : Bool?
var fiscalExterior : Bool?
var profissao : String?
var telefone : String?
var celular : String?
var endereco : String?
var numero : String?
var complemento : String?
var bairro : String?
var cidade : String?
var estado : String?
var cep : String?
var email : String?
var formaPagamento : PaymentWay?
var banco : BrazilBanks?
var agencia : String?
var contaCorrent : String?
var receberEmail: Bool?


init() {
    self.nomeCompleto = nil
    self.cpf = nil
    self.dataNascimento = nil
    self.grauParentesco = nil
    self.registroGeral = nil
    self.orgãoEmissor = nil
    self.dataExpedicao = nil
    self.estadoCivil = nil
    self.numeroFilhos = nil
    self.faixaRenda = nil
    self.ppe = nil
    self.residenteBrasil = nil
    self.fiscalExterior = nil
    self.profissao = nil
    self.telefone = nil
    self.celular = nil
    self.endereco = nil
    self.numero = nil
    self.complemento = nil
    self.bairro = nil
    self.cidade = nil
    self.estado = nil
    self.cep = nil
    self.email = nil
    self.formaPagamento = nil
    self.banco = nil
    self.agencia = nil
    self.contaCorrent = nil
    self.receberEmail = nil
}

}

I have DAO that manages the document creation easily, but also this Listener that is refreshed at some point

 func listenHabilitacao() {
    self.habilitacaoRef = DAOFirebase.shared.getUserDocumentRef()?.collection("beneficiario").document("habilitacao")
    self.habilitacaoListener = self.habilitacaoRef?.addSnapshotListener({ (habilitacaoSnapshot, error) in
        guard let habilitacao = habilitacaoSnapshot, habilitacao.exists else {
            return
        }
        if !(habilitacao.data()?.isEmpty)! {
            let habilitacaoDecoded : HabilitacaoBeneficiario = try!FirebaseDecoder().decode(HabilitacaoBeneficiario.self, from: habilitacao.data() ?? [:])
            self.form = habilitacaoDecoded
        }
    })
}

And this in other view controller

func listenHabilitacao() {
    self.habilitacaoRef = DAOFirebase.shared.getUserDocumentRef()?.collection("beneficiario").document("habilitacao")
    self.habilitacaoListener = self.habilitacaoRef?.addSnapshotListener({ (habilitacaoSnapshot, error) in
        guard let habilitacao = habilitacaoSnapshot, habilitacao.exists else {
            return
        }
        
        
        if !(habilitacao.data()?.isEmpty)! {
            let habilitacaoDecoded : HabilitacaoBeneficiario = try!FirebaseDecoder().decode(HabilitacaoBeneficiario.self, from: habilitacao.data() ?? [:])
            self.form = habilitacaoDecoded
        }
    })
}

that are updated by this method ( with a little modifications after first issue glance, but still with same issues )

func saveHabilitacaoBeneficiario(habilitacao : HabilitacaoBeneficiario) -> (message :String, firestoreError:FirestoreErrorCode?){
var errorCode : (String, FirestoreErrorCode?) = ("",nil)
// codifica habilitacao para o firestore

    var habilitacaoData : [String : Any] =  try! FirebaseEncoder().encode(habilitacao) as! [String : Any]
    
    habilitacaoData.updateValue(habilitacao.dataExpedicao as Any, forKey: "dataExpedicao")
    habilitacaoData.updateValue(habilitacao.dataNascimento as Any, forKey: "dataNascimento")
    
    // adiciona o documento
    let habilitacaoCollection = self.addUserSubCollectionDocument(forUser: (self.user?.uid)!, subcollectionId: "beneficiario", subDocumentId: "habilitacao", data: habilitacaoData)
    errorCode = (habilitacaoCollection.error.message,habilitacaoCollection.error.firestoreError)
    
    // obtem colecao beneficiario para atualizar lista de requerimentos
    let requirementsRef : DocumentReference? = getUserDocumentRef()?.collection("beneficiario").document("requerimentos")
    requirementsRef?.getDocument(completion: { (document, error) in
        if error != nil {
            errorCode = self.handleFirestoreError(error: error!)
        } else if let document = document {
            // obtem lista de requerimentos
            var requirementsData : [String : Any] = document.data()!
            
            let dataCriacao : Any = requirementsData["dataCriacao"] ?? Timestamp() as Any
            requirementsData.updateValue(dataCriacao, forKey: "dataCriacao")
            requirementsData.updateValue(Timestamp(), forKey: "dataAtualizacao")
            requirementsData.updateValue(true, forKey: "completed")
            
            document.reference.setData(requirementsData, merge: true){
                err in
                if let error = err {
                    errorCode = self.handleFirestoreError(error: error)
                }
            }
        }
    })
    return errorCode
}

You are using FirebaseDecoder, you need to use FirestoreDecoder and Encoder instead

Can't believe it hahaha
Thanks, too similar names!

Funny but I've encountered the same issue after 2 years. Hahaha