-1

Happy Sunday everyone. I have a problem with decoding my data. I can't seem to decode data from when I serialize dictionary strings into an object. Im trying to fetch matches from firebase, and this works for when I fetch user profiles but not with fetching matches.

func fetchMatches(onCompletion: @escaping (Result<[MatchModel], DomainError>) -> ()){
        db.collection("matches").whereField("usersMatched", arrayContains: userId!).getDocuments(completion: {doc, err in
            guard let documentSnapshot = doc, err == nil else{
                onCompletion(.failure(.downloadError))
                return
            }
            var matchList: [MatchModel] = []
            var count = 0
            let maxCount = documentSnapshot.documents.count
            var hasFailed = false
            for document in documentSnapshot.documents{
                if hasFailed{ break }
                
                let decoder = JSONDecoder()
                var dict = document.data()

                for (key, value) in dict {
                                        
                if let value = value as? Timestamp {
                    
                    let formatter = DateFormatter()
                    let newValue = value.dateValue()
                    formatter.dateStyle = .short
                    formatter.timeStyle = .none
                    dict[key] = formatter.string(from: newValue)
                   }
                 }

Up until here I know that everything is going well. Dict contains -

Dictionary
["timestamp": "10/22/22", "usersMatched": <__NSArrayM 0x600002c61680>(
6euZHDmI7PMDcCmft5MfxUW27jI3,
tbcB0ay0YEgZcY9UsZ00WjZ9h893
)
]

data below prints out 105 bytes, so with that information I know that it isn't empty and that JSONSerialization did its job of converting dict into an object. But then when I try to decode it into FirestoreMatch.self match returns empty

 if let data = try? JSONSerialization.data(withJSONObject: dict, options:[]){   

do{       
 let match = try? decoder.decode(FirestoreMatch.self, from: data)
            
let matchId : String = match!.usersMatched.filter{$0 != self.userId!}.first!

... }
catch{ 
print(error)

Error returns:

typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "timestamp", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil))

This is my FirestoreMatch struct

struct FirestoreMatch: Codable{
    let usersMatched: [String]
    let timestamp: Date
}

Do I require more information for my struct? Im not sure why match returns nil

  • Your post doesn't make sense to me: `let decoder = JSONDecoder()` and `var dict = document.data()` You create an instance of JSONDecoder in your variable decoder, and then don't use it. Then you have some called called document that you don't explain, and call a method data() on that object, and don't explain your data() method either. What is document? A struct? Show us that struct. What is the method data() on document? Show us that code. You also need to show us your definition of FirestoreMatch. Is that a struct that you've made conform to the Codable protocol? – Duncan C Oct 23 '22 at 18:39
  • Thanks for your comment @DuncanC , I've included more information. Document is a document i retrieve from getDocument from my database. Document.data() returns the information from within that document and stores it in dict, it contains the time stamp and matches of that document which is the Firebasematch struct. Thanks for taking the time to ask for information I hope this helps. – Anthony contreras Oct 23 '22 at 18:56
  • 1
    Don’t use “try?” Use “do try catch” with “print(error)” in the catch, you are just ignoring errors right now – lorem ipsum Oct 23 '22 at 18:58
  • 1
    use `try` not `try?` as that will give an informative error. At the moment you're just throwing all the helpful info away. – flanker Oct 23 '22 at 19:03
  • Thats awesome thank you @loremipsum and flanker , I ended up getting this error ----->> typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "timestamp", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil)) – Anthony contreras Oct 23 '22 at 19:09
  • @Anthonycontreras Take a look at [`JSONDecoder.DateDecodingStrategy`](https://developer.apple.com/documentation/foundation/jsondecoder/datedecodingstrategy): `Date` by default tries to decode as a numeric timestamp (a `TimeInterval`, AKA `Double`), but you can pass the `Decoder` a `DateFormatter` to use to parse the date from a string instead. – Itai Ferber Oct 23 '22 at 19:19
  • Thank you @itaiFerber , The JSONDecoder link was very useful and gave me more insight on what to look for. I was able to resolve my issue by passing a string literal into my dateformatter and then using that as my decoding strategy. thanks again! – Anthony contreras Oct 23 '22 at 20:14

1 Answers1

0

Thank you @itaiFerber @flanker @loremipsum and @duncanC , I was able to resolve my issue by utilizing

 let dateFormatter = DateFormatter()
 dateFormatter.dateFormat = "mm/dd/yy"
 decoder.dateDecodingStrategy = .formatted(dateFormatter)
  • 1
    I’m glad you found a solution. For completeness, you still need to expand your question to show how you are using `JSONDecoder`. In your `fetchMatches()` function you create one and then don’t use it. You also haven’t provided enough information about your `Document` type and the `Document.data()` function. – Duncan C Oct 23 '22 at 22:05
  • 1
    You should include the relevant parts of your `Document` type in your question (not in comments. It’s very hard for your readers, current an future, to get the gist of the problem if they have to read your original question and a bunch of follow-on comments in order to understand the context of the question.) – Duncan C Oct 23 '22 at 22:06
  • 1
    One additional note: you need to also set the [`locale`](https://developer.apple.com/documentation/foundation/nsdateformatter/1411973-locale?language=swift) property on the date formatter to a _fixed_ locale so this produces reproducible results. See [QA1480](https://developer.apple.com/library/archive/qa/qa1480/_index.html) from the Apple docs for more on why this is necessary; tl;dr: you need to assign the `en_US_POSIX` locale for fixed date formats. – Itai Ferber Oct 23 '22 at 22:52