티스토리 뷰

Swift

Swift ) DateDecoding(Encoding)Strategy

Zedd0202 2018. 1. 23. 16:18
반응형

안녕하세요 :) Zedd입니다.

< 왕초보를 위한 Codable - CodingKey >글에서 DateDecodingStrategy의 각 Strategy가 어떤 역할?...어떤 포맷??인지 궁금해져서....

위 글을 읽고오시면 이해가 더 잘되실수도

Date와 관련된 Strategy는 DateDecodingStrategy말고도 DateEncodingStrategy도 있어요!!! 저는 Decoding으로 설명할거에요 :) Encoding에서도 똑같으니..!!! 각 Strategy가 어떤 역할을 하는건지만 보면 될 것 같습니당


DateDecodingStrategy



저번시간에 올렸듯이



DateDecodingStrategy에는 굉장히 많은 전략이 있습니다.

DateDecodingStrategy라는 enum에 여러 case들이 있는 걸 볼 수 있죠? 밑에 더 있는데..캡쳐가 안대씀

그럼 하나하나 볼게요 XD


deferredToDate 

이건 default Strategy에요!! 딱히..설명은 없습니다...ㅎㅎ


secondsSince1970

이건 1970년 1월 1일 자정부터 UTC로 초단위로 date를 인코딩/디코딩 하는 전략이에요. 

( UTC : Coordinated Universal Time, 협정세계시. 1972년 1월 1일부터 시행된 국제표준시에요. UTC는 그리니치 평균시(Greenwich Mean Time, GMT로 불리기도 하는데, UTC와 GMT는 초의 소숫점단위에서만 차이가 나기 때문에 혼용되어서 사용되곤 한대요 :) 기술적인 표기에서는 UTC가 사용된다고 합니다. GMT는 아시는 분들도 많겠지만, 런던을 기점, 웰링턴을 종점으로 하는 UTC의 빠른시간대입니다. 공식표현은 UTC가 맞아요. )


그러니까 쉽게 생각하세요! 아 ㅇㅇ 1970년 1월 1일 00:00:00부터 몇초가 경과했는지를 나타내는 겁니다.

예를들어 1515083815. 이런 숫자죠. (숫자는 위키백과에서 가져왔어요! https://ko.wikipedia.org/wiki/유닉스_시간)

< 왕초보를 위한 Codable - CodingKey >글에서 Date는 


1
"birth_date" : "2017-01-22T23:16:50+0000"
cs


이런 포맷이었는데(iso8601전략을 사용했었죠?), 만약 


1
"birth_date" : 1515083815
cs


이런 포맷이었다고 생각해봅시다. 

그러면  iso8601전략을 사용하면 안되고!!!!!! secondsSince1970전략을 사용해야겠죠? 


1
2
3
4
5
6
7
let decoder = JSONDecoder()
 
decoder.dateDecodingStrategy = .secondsSince1970
 
....(중략)
 
print(myPerson.birthday)//2018-01-04 16:36:55 +0000
cs



이렇게 해주면!! 이렇게 print가 된답니다. 

알아서 이쁘게 변환해서 보여주네요. 

디코딩 하는과정은 < 왕초보를 위한 Codable >이나 < 왕초보를 위한 Codable - CodingKey >에서 설명했으니 중략하도록 할게요 :)




● millisecondsSince1970

위에랑 상당히 비슷하죠? 이건 그냥 millisecond단위로 날짜를 인코딩/디코딩 할거냐. 이거에요.

second에서 1000만 곱해주면 되겠죠? 밀리세컨드니까 ㅇㅇ


1
"birth_date" : 1515083815000.0
cs


위에서 사용했던 1515083815에 1000만 곱해줬어요. 소수점을 그냥 넣어봤는데 소수점을 넣든 안넣든 상관없습니다.

둘다 잘 디코딩해줘요!!!

이렇게 값을 해놓고 secondsSince1970라고 전략을 지정해놓으면..안되겠죠? 

정말 이상한 값이 나온답니다 :)..

(위 값으로 하면 49981-02-04 07:16:40 +0000...)


1
2
3
4
5
6
7
"birth_date" : 1515083815000.0
 
let decoder = JSONDecoder()
 
decoder.dateDecodingStrategy = .millisecondsSince1970
 
print(myPerson.birthday)//2018-01-04 16:36:55 +0000
cs


이렇게 잘 나온답니다 :)



iso8601

iso8601은 < 왕초보를 위한 Codable - CodingKey >글에서 봤죠? 




이런식의 포맷이 iso8601포맷이라고 할 수 있어요. 

iso8601은 날짜와 시간에 관련된 데이터 교환을 다루는 국제 표준이라고 합니다 국제표준화기구(ISO)에 의해 공표되었으며, 1988년에 처음으로 공개되었다고 해요 :) 

iso8601에는 표기법이 여러개가 있는데, 

연월일표기법(YYYY-MM-DD),연과 연중 일수 표기법(YYYY-DDD), 연과 주의 주중 일수 표기법(YYYY-Www-D)이런것들이 있다고 하는데


일단 안먹힙니다...예를들어 2018-01-23이렇게 지정하고 iso8601로 전략을 지정해줘도 인식을 못해요 ㅠㅠ 

위 그림의 포맷이어야만 인식을...합니다. 


1
"birth_date" : "1981-02-22T09:00:00+0900"
cs


이렇게 뒤에 시간대를 붙히는 것도 가능해요!!(인식이 된다는 말) 


1
2
3
4
5
6
7
"birth_date" : "1981-02-22T09:00:00+0900"
 
let decoder = JSONDecoder()
 
decoder.dateDecodingStrategy = .iso8601
 
print(myPerson.birthday)//1981-02-22 00:00:00 +0000
cs


이렇게 잘 출력이 됩니다 :)






● formatted(DateFormatter)

"Date를 주어진 포맷터에 의해 파싱된 문자열로 디코드 합니다."

라는게 이 case의 정의입니다!

오 뭔가 엄청 강력해보이는데..

만약에!!! 제가  


1
"birth_date" : "2018-01-23"
cs


이러한 포맷으로 Date가 있다고 생각해볼게요.

이거 어케 인코딩/디코딩할거냐 ㅡㅡ어쩔거냐 ㅡㅡ

이럴때 바로 formatted(DateFormatter) 전략을 사용하면 됩니다.


1
"birth_date" : "2018-01-23"
cs


DateFormatter라는게 있는건 아시죠?


1
 let formatter = DateFormatter()
cs


이런거...이걸 저 파라미터에 넣어주면(formatted(DateFormatter)) 나만의 포맷을 인식하게 할 수 있다~이거죠


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
extension DateFormatter {
 
    static let yyyyMMdd: DateFormatter = {
 
        let formatter = DateFormatter()
 
        formatter.dateFormat = "yyyy-MM-dd"
 
        formatter.calendar = Calendar(identifier: .iso8601)
 
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
 
        formatter.locale = Locale(identifier: "ko_kr")
 
        return formatter
 
    }()
 
}
cs


이렇게 DateFormatter를 extension해서!!


1
formatter.dateFormat = "yyyy-MM-dd"
cs


이게 핵심이죠. 


1
"birth_date" : "2018-01-23"
cs


제 JSON이 이런 포맷이니까요!!! 년도가 나오고, 월-일

이제!!

1
2
3
4
5
6
7
"birth_date" : "2018-01-23"
 
let decoder = JSONDecoder()
 
decoder.dateDecodingStrategy = .formatted(DateFormatter.yyyyMMdd)
 
print(myPerson.birthday)//2018-01-23 00:00:00 +0000
cs


파라미터에 우리가 만든 fomatter를 넣으면 이런식으로 잘!!!나오게 되는거죠. XD


1
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
cs


DateFormatter를 이렇게 바꾸게되면


1
2
3
4
5
6
7
"birth_date" : "2018-01-23 18:15:32"
 
let decoder = JSONDecoder()
 
decoder.dateDecodingStrategy = .formatted(DateFormatter.yyyyMMdd)
 
 print(myPerson.birthday)//2018-01-23 18:15:32 +0000
cs


이런식으로 할 수 있는거죠 :)




 custom((Decoder) throws -> Date)


마지막입니다 :) 커스텀! 뭔가 사용자정의? 그런 것 같네요.

사용자정의 함수(클로져)를 호출하여 사용자 지정 Date포맷을 지정하는 전략이에요. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
 
    let container = try decoder.singleValueContainer()
 
    let dateStr = try container.decode(String.self)
 
    var date: Date?
 
    if dateStr.count == 10 {
 
        let formatter = DateFormatter()
 
        formatter.dateFormat = "yyyy-MM-dd"
 
        date = formatter.date(from: dateStr)!
 
    }
 
    return date!
 
})
cs


이런식으로?........여기에 올라온 예제인데, 음..이렇게 카운트로 세지 말고도 다른방법으로 하면 더 효율적이겠죠? 예를들어 여기처럼 아예 DateDecodingStrategy를 extension하는 방식? 이 코드는 엄청 길어서...위 코드를 가져왔는데

일단 custom이라는 case를 어떻게 활용하는지에 대해서만 보시면 될 것 같아요!!!!


아무튼 DateDecodingStrategy를 이해하는데 도움이 되었으면 좋겠습니다.

틀린 부분이 있다면 댓글이나 PC화면 오른쪽 하단에 있는 채널서비스로 메세지 주세요 :)

안녕!!


출처 :

http://dinesql.blogspot.kr/2015/05/sql-server-brain-basher-of-week-010.html

https://stackoverflow.com/questions/43297931/swift-3-jsonserialization-serialize-dictionary-contain-character

https://useyourloaf.com/blog/swift-codable-with-custom-dates/

반응형

'Swift' 카테고리의 다른 글

Swift4.1 ) flatMap -> compactMap  (2) 2018.03.11
Swift ) API Design Guidelines  (0) 2018.01.25
Swift ) 왕초보를 위한 Codable - CodingKey  (5) 2018.01.23
Swift ) NSCountedSet  (2) 2018.01.22
Swift ) Access Control(접근제어) - (2)  (1) 2018.01.17