JSONDecoder 구문 분석 시간의 DateDecodingStrategy

JSONDecoder 직렬 API에서 반환 된 JSON 데이터를 사용할 때 일반적으로 앱에서 시간 계산 함수를 사용할 수 있도록 시간 필드의 데이터를 날짜 유형에 매핑합니다. 그러나 API가 반환하는 시간에는 많은 형식이 있으므로 JSONDecoder에 시간 형식을 알려야 시간을 구문 분석하고 날짜 형식으로 저장할 수 있습니다.

위의 세 API는 각각 다른 시간 형식을 반환합니다.

JSONDecoder 구문 분석 시간의 DateDecodingStrategy

JSONDecoder의 dateDecodingStrategy를 통해 JSON의 시간 형식을 설정할 수 있습니다.

dateDecodingStrategy의 유형은 DateDecodingStrategy이며 다음과 같은 형식을 설정할 수 있습니다. 다음으로 몇 가지 일반적인 시간 형식을 실제 예제와 함께 소개하겠습니다.

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

예 : iTunes API.

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()
}

secondsSince1970

예 : IG API.

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

백그라운드에서 반환 된 시간이 숫자 문자열 인 경우 1970.1.1에서 초 수일 가능성이 높습니다. 먼저 Xcode 플레이 그라운드에서 Date를 생성하고 timeIntervalSince1970 매개 변수를 백엔드에 전달하여 생성 된 Date가 합리적인지 테스트 할 수 있습니다.

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()
}

밀리 초 Since1970

예 : covid19uk API.

https://api.covid19uk.live/historyfigures

앞서 언급했듯이 백그라운드에서 반환 된 시간이 일련의 숫자 인 경우 1970.1.1의 초 수일 확률이 높지만 1970.1.1의 밀리 초 수도있을 수 있습니다. 따라서 secondsSince1970을 사용하여 매우 많은 수의 비정상적인 시간을 얻는 경우 millisecondsSince1970을 다시 시도하는 것을 잊지 마십시오.

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()
}

포맷

예 : 마스크 API.

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()
}

커스텀

예 : Dcard API.

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

다행히 iOS SDK는 ISO8601DateFormatter를 제공하여 소수점으로 iso8601을 구문 분석 할 수 있습니다. 그러나 ISO8601DateFormatter는 DateFormatter가 아니므로 .formatted ()에서 ISO8601DateFormatter 개체를 전달할 수 없습니다.

따라서 우리는 마지막 방법에 의존하여 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: "")
   }
})

withFractionalSeconds를 사용하여 ISO 8601 초를 소수로 구문 분석합니다.

Suggested posts

“그 작은 섬이 모든 것을 바꾼다”

탑승자 경험을 향상시키기 위해 Lyft 실시간 활동을 설계한 방법

“그 작은 섬이 모든 것을 바꾼다”

차량 공유를 위한 게임 체인저 Lyft에서 우리가 하는 모든 일 중에서 라이더와 운전자 간의 픽업 안무는 가장 복잡하고 결과적인 것 중 하나입니다. 이 안무를 잘하는 것은 Lyft가 많은 일을 잘하는 것에 달려 있지만 단순히 라이더가 속도를 유지하는 것이 필수적입니다.

앱 라이프사이클

앱 라이프사이클

: 앱 시작부터 종료까지 주기 : 메모리나 데이터 관리로 사용성 ⬆️ 보안 처리 가능 UIApplication, AppDelegate 상황 : AppDelegate 객체가 UIApplication 객체에서 보낸 메시지를 받아 각각 실행하는 기능 정의 Not Running : 앱이 실행되고 있지 않은 상태Inactive : 앱이 실행되고 있지만 이벤트가 수신되지 않은 상태활성: 앱이 실행 중이고 이벤트가 발생한 상태백그라운드: 앱이 백그라운드에 있지만 코드가 실행 중인 상태서스펜드: 앱이 실행 중인 상태 AppDelegate.swift 파일 SceneDelegate에서 델리게이트 기능이 될 코드를 백그라운드에서 실행하지 않고 실행 iOS 13 이상부터 지원하는 다중 씬 기능에 잘 대응하기 위해 AppDelegate / SceneDelegate AppDelegate 1.

Related posts

전화번호만 있으면 누구나 추적 | OSINT 조사

전화번호만 있으면 누구나 추적 | OSINT 조사

OSINT 수사관, CTF 플레이어 또는 단순히 스팸 전화를 받는 사람일 수 있습니다. 광고에서 본 번호를 확인하려는 사람.

"마리아나 해구 공개: 심연의 무서운 숨겨진 진실 공개"

"마리아나 해구 공개: 심연의 무서운 숨겨진 진실 공개"

소개:용감한 독자 여러분, 지구의 가장 어두운 곳으로 우리를 데려다 줄 여행에 오신 것을 환영합니다. 이 블로그에서 우리는 Mariana Trench의 수수께끼 같은 세계를 탐구하여 숨겨진 비밀을 밝히고 그 표면 아래에 있는 뼛속까지 오싹해지는 진실을 밝혀냅니다.

카우보이의 거짓말

거대 기업이 미국인에게 강력한 거짓을 판매하는 방법

카우보이의 거짓말

햇빛의 첫 번째 광선이 평원의 서리가 내린 풀을 비추는 서쪽 언덕의 눈부신 황금빛 아침입니다. 온화하고 거대한 새까만 앵거스 소 떼가 일출을 배경으로 윤곽을 그리며 다져진 길을 따라 모두가 잘 아는 지역으로 향합니다. 조식 바.

느린 침식: 사람들이 경력을 낭비하는 방식 공개

느린 침식: 사람들이 경력을 낭비하는 방식 공개

오늘날과 같이 급변하고 경쟁이 치열한 세상에서 경력은 개인의 성장, 재정적 안정 및 전반적인 삶의 만족도에 중요한 역할을 합니다. 그러나 많은 사람들은 침체와 불만족의 끊임없는 순환에 휩싸여 직업 생활에서 점차 쇠퇴하고 있습니다.