DateDecodingStrategy do tempo de análise do JSONDecoder

Quando usamos os dados JSON retornados pela API serial JSONDecoder, geralmente mapeamos os dados no campo de hora para o tipo de data, para que o aplicativo possa usar algumas funções de cálculo de tempo posteriormente. No entanto, a hora retornada pela API tem muitos formatos, então devemos informar ao JSONDecoder o formato da hora para que ele possa analisar a hora e armazená-la como um tipo de data.

As três APIs acima retornam formatos de hora diferentes, respectivamente

DateDecodingStrategy do tempo de análise do JSONDecoder

Podemos definir o formato de hora de JSON por meio de dateDecodingStrategy de JSONDecoder.

O tipo de dateDecodingStrategy é DateDecodingStrategy. Os formatos que podemos definir são os seguintes. A seguir, vamos apresentar vários formatos de hora comuns com exemplos práticos.

enum DateDecodingStrategy {
case deferredToDate
case secondsSince1970
case millisecondsSince1970
case iso8601
case formatted(DateFormatter)
case custom((Decoder) throws -> Date)
}

Exemplo: API do iTunes.

https://itunes.apple.com/search?term=beatles&media=music

struct ItunesResult: Decodable {
    let results: [Song]
}
struct Song: Decodable {
    let trackName: String
    let releaseDate: Date
}
if let url = URL(string: "https://itunes.apple.com/search?term=beatles&media=music") {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        if let data = data, let itunesResult = try? decoder.decode(ItunesResult.self, from: data) {
            print(itunesResult.results.first)
        }
    }.resume()
}

segundosSince1970

Exemplo: IG API.

https://www.instagram.com/lepetitprinceofficiel/?__a=1

Quando o tempo retornado em segundo plano é uma sequência de números, há uma grande probabilidade de que esteja a poucos segundos de janeiro de 1970. Também podemos gerar a Data no playground do Xcode primeiro e passar o parâmetro timeIntervalSince1970 para o backend para testar se a Data gerada é razoável.

struct IGResult: Decodable {
    let graphql: Graphql
}
struct Graphql: Decodable {
    let user: User
}
struct User: Decodable {
    let edgeOwnerToTimelineMedia: TimelineMedia
}
struct TimelineMedia: Decodable {
    let edges: [Edge]
}
struct Edge: Decodable {
    let node: Node
}
struct Node: Decodable {
    let takenAtTimestamp: Date
}
if let url = URL(string: "https://www.instagram.com/lepetitprinceofficiel/?__a=1") {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        decoder.dateDecodingStrategy = .secondsSince1970
        if let data = data, let igResult = try? decoder.decode(IGResult.self, from: data) {
            print(igResult.graphql.user.edgeOwnerToTimelineMedia.edges.first?.node.takenAtTimestamp)
        }
    }.resume()
}

millisecondsSince1970

Exemplo: API covid19uk.

https://api.covid19uk.live/historyfigures

Conforme mencionado anteriormente, quando o tempo retornado pelo plano de fundo é uma sequência de números, há uma grande probabilidade de que seja o número de segundos de 1970.1.1, mas também pode ser o número de milissegundos de 1970.1.1. Portanto, se você usar secondsSince1970 para obter um número muito grande de tempo anormal, lembre-se de tentar milissegundosSince1970 novamente.

struct CovidData: Decodable {
    let data: [Record]
}
struct Record: Decodable {
    let date: Date
}
if let url = URL(string: "https://api.covid19uk.live/historyfigures") {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .millisecondsSince1970
        if let data = data, let covidData = try? decoder.decode(CovidData.self, from: data) {
            print(covidData.data.first?.date)
        }
    }.resume()
}

formatado

Exemplo: API de máscara.

https://quality.data.gov.tw/dq_download_json.php?nid=116285&md5_url=2150b333756e64325bdbc4a5fd45fad1

struct Mask: Decodable {
    let name: String
    let time: Date
    
    enum CodingKeys: String, CodingKey  {
        case name = "醫事機構名稱"
        case time = "來源資料時間"
    }
}
if let url = URL(string: "https://quality.data.gov.tw/dq_download_json.php?nid=116285&md5_url=2150b333756e64325bdbc4a5fd45fad1") {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        let decoder = JSONDecoder()
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy/MM/dd HH:mm:ss"
        decoder.dateDecodingStrategy = .formatted(dateFormatter)
        if let data = data, let masks = try? decoder.decode([Mask].self, from: data) {
            print(masks.first)
        }
    }.resume()
}

personalizadas

Exemplo: API Dcard.

https://dcard.tw/_api/posts?popular=true

Felizmente, o iOS SDK fornece ISO8601DateFormatter para ajudar a analisar iso8601 com um ponto decimal. No entanto, ISO8601DateFormatter não é um DateFormatter, não podemos passar o objeto ISO8601DateFormatter em .formatted ().

Portanto, só podemos usar o truque matador, contando com o último método, escrever o programa de análise de tempo com encerramento, por meio do caso personalizado de DateDecodingStrategy.

struct Dcard: Decodable {
    let title: String
    let createdAt: Date
}
if let url = URL(string: "https://dcard.tw/_api/posts?popular=true") {
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        let decoder = JSONDecoder()
        let dateFormatter = ISO8601DateFormatter()
        dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
        decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
            let container = try decoder.singleValueContainer()
            let dateString = try container.decode(String.self)
            if let date = dateFormatter.date(from: dateString) {
                return date
            } else {
                throw DecodingError.dataCorruptedError(in: container, debugDescription: "")
            }
        })
        if let data = data, let dcards = try? decoder.decode([Dcard].self, from: data) {
            print(dcards.first)
        }
    }.resume()
}

      

let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]

decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
   let container = try decoder.singleValueContainer()
   let dateString = try container.decode(String.self)
   if let date = dateFormatter.date(from: dateString) {
        return date
   } else {
        throw DecodingError.dataCorruptedError(in: container, debugDescription: "")
   }
})

Use withFractionalSeconds para analisar ISO 8601 segundos com decimais

Suggested posts

“Aquela pequena ilha muda tudo”

Como projetamos as Lyft Live Activities para elevar a experiência do passageiro

“Aquela pequena ilha muda tudo”

Uma virada de jogo para o compartilhamento de viagens De todas as coisas que fazemos na Lyft, coreografar pickups entre passageiros e motoristas é uma das mais complexas e consequentes. Pregar essa coreografia depende de Lyft fazer muitas coisas bem, mas simplesmente manter os pilotos atualizados é essencial.

Ciclo de vida do aplicativo

Ciclo de vida do aplicativo

: Ciclo do lançamento do aplicativo ao desligamento: Usabilidade gerenciando memória ou dados ⬆️ A segurança pode ser processada UIApplication, situação AppDelegate:Define as funções que o objeto AppDelegate recebe msg enviada do objeto UIApplication e executa cada uma Não em execução: O estado em que o aplicativo não está em execuçãoInativo: O estado em que o aplicativo está em execução, mas nenhum evento é recebidoAtivo: O estado em que o aplicativo está em execução e ocorre um eventoBackground: O estado em que o aplicativo está em segundo plano, mas o código está sendo executadoSuspened: O estado em que o aplicativo está no plano de fundo e sem execução de código para delegar funções no arquivo AppDelegate.swift SceneDelegate Para responder bem à função de cena múltipla suportada a partir do iOS 13 AppDelegate / SceneDelegate AppDelegate 1.

Related posts

Criando um ambiente de trabalho seguro

Criando um ambiente de trabalho seguro

“Ele vai me proteger quando eu estiver em perigo. Ele me esconderá em sua tenda.

O primeiro livro de uma criança sobre como ficar chapado

O primeiro livro de uma criança sobre como ficar chapado

(Aviso - isso é sátira, com a intenção de ser alegremente subversivo - definitivamente não é para crianças) Você viu sua mãe e seu pai se esconderem na cozinha e fumarem aqueles cigarros fedorentos. Eles dizem a você.

Chega de senhas — como as senhas substituirão sua senha

Chega de senhas — como as senhas substituirão sua senha

Para evitar ambigüidade, os seguintes termos serão usados; Autenticador; O celular que está sendo utilizado para fazer o login no Site; O site ou aplicativo que o usuário está usando para fazer a solicitação de login do Serviço; O fornecedor que fornece o serviço fornecido, por exemplo

Dois anos em design - O bom, o mau e o feio…

Dois anos em design - O bom, o mau e o feio…

“Ei, Siri, toque Me Dive, de Olivia Dean.” Era maio de 2021 quando comecei meu estágio na Future Academy Africa em Akure, Nigéria.