SWIFT4가 나오면서 Codable 프로토콜이 새로 나옴
swiftyJSON은 가볍게 사용하기는 좋지만 많은 데이터를 처리하기에는 시간이 오래 걸린다.
JSONSerialization이 가장 빠르게 처리되기는 하지만 코드가 복잡해서 JSONDecoder를 많이 선택한다.
우리가 오픈소스로 데이터를 처리했다면 이제는 JSONDecoder 라는 스위프트에서 제공해주는 클래스로 처리를 해보자!
🔆 Typealias를 통해서 Encoding, Decoding을 합친 것이 Codable
Encoding : [struct -> JSON] struct/class를 서버에게 보내기 위해 외부 데이터로 변경
Decoding : [JSON -> struct] 서버에서 받은 외부 데이터를 우리가 사용할 수 있게 struct/class
JSON을 담아주기 위해 구조체에 Decodable 프로토콜 채택
struct Quote: Decodable {
let quote: String
let author: String
}
Decoder의 초기화 구문을 보면 throws를 에러를 던지고 있기 때문에 do-try-catch 구문을 써야 한다는 걸 알 수 있다.
🔰 공식문서에서 나온 사용 방법은
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
let json = """
{
"name": "Durian",
"points": 600,
"description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)
print(product.name) // Prints "Durian"
Decoding
만약 프로퍼티명을
- 좀 더 구체적으로 쓰고 싶어서 or
- JSON 키값에 snakecase로 되어 있다고 해서
SON 키값과 다르게 구조체 프로퍼티명을 다르게 써주면 오류가 발생한다. keyNotFound
1). 해결해주기 위한 가장 쉬운 전략은 옵셔널로 바꾸는 것 - but, nil로 출력되어서 원하는 해결책은 아니다.
2). key를 decoding전략을 세워준다. : keyDecodingStrategy
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
단, 구조체 프로퍼티의 대소문자를 기준으로 구분하니까 주의해야 함
author_name이면 authorName이라고 해야지 authornAme이라고 하면 안됨
3). 좀 더 프로퍼티를 간단하게 또는 완전히 다르게 만들고 싶다면?
: 🔆CodingKey 라는 내부적으로 구현된 프로토콜을 채택한 열거형 사용
struct Quote: Decodable {
let comment: String
let author: String
enum CodingKeys: String, CodingKey { // 내부적으로 선언되어 있는 열거형
case comment = "quote_content"
case author = "author_name"
}
}
* 만약 JSON 키랑 프로퍼티가 같으면 따로 명시해주지 않아도 된다.
*서버 응답값을 좀 변경해서 모델로 넣고 싶은 경우
4-1). 서버에서 넘어오는 데이터의 개수는 3개인데 받고자 하는 데이터는 2개인 경우
- 그냥 냅둬도 상관없음
4-2). 서버에서 넘어오는 데이터의 개수는 3개인데 받고자 하는 데이터는 4개인 경우
- 초기화 구문을 사용해서
container라는 박스를 하나 만들고, 열거형 각각의 case가 들어있고, forKey에 해당 case들이 들어간다.
그리고 구조체의 프로퍼티에 디코딩되어 들어가고,
어떤 타입을 기반으로 디코딩되어 들어가냐면 - String.self / Int.self / Bool.self를 기반으로 해서 들어간다는 것이다.
- JSON 값이 null인 경우에는 decodeIfPresent를 통해 nil 병합연산자로 대응
struct Quote: Decodable {
let comment: String
let author: String
let like: Int
let isInfluencer: Bool // like가 10,000개 이상인 경우
enum CodingKeys: String, CodingKey { // 내부적으로 선언되어 있는 열거형
case comment = "quote_content"
case author = "author_name"
case like = "likeCount"
case isInfluencer = "isInfluencer"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
comment = try container.decode(String.self, forKey: .comment)
author = try container.decodeIfPresent(String.self, forKey: .author) ?? "작자미상"
like = try container.decode(Int.self, forKey: .like)
isInfluencer = (10000...).contains(like) ? true : false // like가 10,000개 이상인 경우
}
}
Encodable
서버한테 우리의 데이터를 JSON 형식으로 바꿔서 보내주려면?
구조체 배열을 Encoding해준다.
구조체 -> Data -> String
Encoding 전략
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
encoder.dateEncodingStrategy = .iso8601
우리가 아는 JSON 형식으로 해주려면 - .outputFormatting = .prettyPrinted
근데 날짜는 왜 저럼? - 표준규격임
익숙한 방식으로 바꾸려면 - .dateEncodingStrategy = .iso8601
iso8601 : 날짜와 시간과 관련된 데이터 교환을 다루는 국제 표준
.formatted와 DateFormatter를 통해서 날짜 형식을 바꿔줄 수도 있다.
let encoder = JSONEncoder()
let format = DateFormatter()
format.locale = Locale(identifier: "ko-KR")
format.dateFormat = "MM월 dd일 EEEE"
encoder.dateEncodingStrategy = .formatted(format)
'⭐️ 개발 > iOS & Swift' 카테고리의 다른 글
[iOS] 안간단한 MVVM 안간단하게 톺아보기 (3) | 2022.08.31 |
---|---|
[iOS] URLSession(1) (0) | 2022.08.30 |
[Swift] Error Handling (4) | 2022.08.26 |
[Swift] WMO - Swift 성능 최적화 (1) | 2022.08.26 |
[Swift] Realm 진짜.그냥.간단.정리 (0) | 2022.08.24 |