簡體   English   中英

iOS 錯誤“JSON 寫入 (FIRTimestamp) 中的類型無效”

[英]iOS error 'Invalid type in JSON write (FIRTimestamp)'

我正在嘗試將我的數據 map 轉換為 Model。我在其中使用 Firestore 快照偵聽器來獲取數據。 在這里,我正在獲取數據並將其映射到“用戶”model

            do{
                let user = try User(dictionary: tempUserDic)
                print("\(user.firstName)")
            }
            catch{
                print("error occurred")
            }

這是我的Model:

struct User {
    let firstName: String
//    var lon: Double = 0.0
//    var refresh:Int = 0
//    var createdOn: Timestamp = Timestamp()
}

//Testing Codable
extension User: Codable {
    init(dictionary: [String: Any]) throws {
        self = try JSONDecoder().decode(User.self, from: JSONSerialization.data(withJSONObject: dictionary))
    }
    private enum CodingKeys: String, CodingKey {
        case firstName = "firstName"
    }
}

如果我錯了,請糾正我。

崩潰是因為我在數據中得到“時間戳”。

從偵聽器獲取的數據:

用戶詞典

[\"firstName\": Ruchira,
 \"lastInteraction\": FIRTimestamp: seconds=1576566738 nanoseconds=846000000>]"

如何將 map“時間戳”轉換為 Model?

試過“CodableFirstore” https://github.com/alickbass/CodableFirebase

我通過將FIRTimestamp字段轉換為Double (秒)來解決這個問題,因此JSONSerialization可以相應地解析它。

 let items: [T] = documents.compactMap { query in
   var data = query.data() // get a copy of the data to be modified.

   // If any of the fields value is a `FIRTimestamp` we replace it for a `Double`.
   if let index = (data.keys.firstIndex{ data[$0] is FIRTimestamp }) {

     // Convert the field to `Timestamp`
     let timestamp: Timestamp = data[data.keys[index]] as! Timestamp

     // Get the seconds of it and replace it on the `copy` of `data`.
     data[data.keys[index]] = timestamp.seconds

    }

    // This should not complain anymore.
    guard let data = try? JSONSerialization.data(
       withJSONObject: data, 
       options: .prettyPrinted
    ) else { return nil }

    // Make sure your decoder setups the decoding strategy to `. secondsSince1970` (see timestamp.seconds documentation).
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .secondsSince1970
    return try? decoder.decode(T.self, from: data)
 }

// Use now your beautiful `items`
return .success(items)

一種方法是創建類型Dictionary的擴展,將字典轉換為任何其他類型,但自動將DateTimestamp類型修改為可寫的 JSON 字符串。

這是代碼:

extension Dictionary {

    func decodeTo<T>(_ type: T.Type) -> T? where T: Decodable {
        
        var dict = self

        // This block will change any Date and Timestamp type to Strings
        dict.filter {
            $0.value is Date || $0.value is Timestamp
        }.forEach {
            if $0.value is Date {
                let date = $0.value as? Date ?? Date()
                dict[$0.key] = date.timestampString as? Value
            } else if $0.value is Timestamp {
                let date = $0.value as? Timestamp ?? Timestamp()
                dict[$0.key] = date.dateValue().timestampString as? Value
            }
        }

        let jsonData = (try? JSONSerialization.data(withJSONObject: dict, options: [])) ?? nil
        if let jsonData {
            return (try? JSONDecoder().decode(type, from: jsonData)) ?? nil
        } else {
            return nil
        }
    }
}

.timestampString方法也在Date類型的擴展中聲明:

extension Date {
    
    var timestampString: String {
        Date.timestampFormatter.string(from: self)
    }
    
    static private var timestampFormatter: DateFormatter {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        dateFormatter.timeZone = TimeZone(identifier: "UTC")
        return dateFormatter
    }
}

用法,就像問題的情況一樣:

let user = tempUserDic.decodeTo(User.self)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM