# JSON & Codable

Borysarang·2022년 6월 16일
0

swift

목록 보기
1/7

JSON & Codable

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate.

JSON(JavaScript Object Notation)은 데이터 교환을 위한 가벼운 포맷이다. 인간에게는 읽히기 쉬우며, 기계가 이를 변환하기 좋다. 으로 구성된 데이터 쌍의 나열로 볼 수 있다.

JSON 공식 문서

Codable, CodingKey

스위프트에서 JSON 데이터를 사용하려면 인코딩 및 디코딩 과정이 필요하다. 스위프트의 인스턴스를 외부 표현(공식 문서상 an external representation)으로 변환하기 위해서는 객체가 EncodableDecodable 프로토콜을 채택해야 한다.



또 Swift의 구조체(클래스)는 기본적으로 카멜 케이스를 권장하고 있다. 따라서 스네이크 케이스로 구현되어있는 JSON 데이터와는 키값이 서로 다르게 인식된다. 사용하고자 하는 구조체에 CodingKey 프로토콜을 채택하여 키값을 매핑할 수 있다.

예제로 아래와 같은 구조체 및 JSON 파일을 서로 변환할 것이다.

struct PetElement: Codable {
    let petName: String
    let age: Int
    let species: String

    enum CodingKeys: String, CodingKey {
        case petName = "pet_name"
        case age, species
    }
}
typealias Pet = [PetElement]
[ // items.json
    {
        "pet_name":"보리",
        "age":12,
        "species":"강아지"
    },
    {
        "pet_name":"쉐리",
        "age":4,
        "species":"고양이"
    }
]

구조체의 애완동물 이름은 petName이지만 Json 파일에서는 pet_name으로 되어있고 이를 위해 CodingKey로 매핑 해주는 것을 볼 수 있다. 나머지 프로퍼티는 String 타입으로 rawValue가 있기 때문에 지정해주지 않아도 매핑이 된다.

Decoding

먼저 프로젝트에 저장된 items.json에는 json타입으로 저장된 데이터가 있다. 여기에 저장된 데이터를 Pet타입의 인스턴스로 디코딩 할것이다.

  1. Json 파일이 저장된 경로를 확인
  2. Data 타입으로 변환
  3. JsonDecoder를 통해 디코딩
  4. 프로퍼티에 변환한 인스턴스 주입

Json 파일 경로 얻기

guard let fileLocation = Bundle.main.url(forResource: fileName, withExtension: extensionName) else {
            return nil
}

위 코드를 통해 items.json 파일의 경로를 불러올 수 있다. 이렇게 얻은 경로는 URL 타입이다.

LLDB로 확인해보니, 현재 시뮬레이터 내부의 데이터경로가 직접적으로 나오게 된다.

Data 타입으로 변환

이제 이렇게 얻은 Json의 경로를 통해 데이터 타입으로 변환한다

do{
    let data = try Data(contentsOf: fileLocation)
    return data
}catch {
    return nil
} 

이때 데이터 타입이 정확하게 어떤건지 궁금해서 개발자 문서를 확인해 보았다.

A byte buffer in memory.
The Data value type allows simple byte buffers to take on the behavior of Foundation objects. You can create empty or pre-populated buffers from a variety of sources and later add or remove bytes. You can filter and sort the content, or compare against other buffers. You can manipulate subranges of bytes and iterate over some or all of them.

내가 이해하기에 메모리의 버퍼, 즉 메모리에 올라간 데이터 나열인데 Json 파일과 인스턴스 타입을 오갈 때 메모리 버퍼에 기계어에 가까운 형태로 올라가 있어야 하는데 이때 스위프트는 Data 타입으로 저장하는듯 하다.

실제로 찍어보면 단순 바이트의 정보로만 표현이 되고 있었다.

Decoding

이제 Json을 프로그램상 메모리에 로드 했으니(Data 타입으로 불러옴) 이를 우리가 원하는 데이터로 변환해야 한다.

let decoder = JSONDecoder()
do{
    let decodedData = try decoder.decode(Pet.self, from: data ?? Data())
    petList = decodedData
}catch {
    print("error")
    return
}

JSONDecoder를 통해 디코딩을 하면 최종적으로 Pet 인스턴스를 decodedData에 저장하게 된다.
이렇게 저장된 데이터를 출력해보면 정상적으로 PetElement의 배열로 저장되게 된다..!

Encoding

다음과 같은 인스턴스를 JSON 형태로 인코딩 할 것이다.

var EncodedPetList: Pet = []
let groot: PetElement = PetElement(petName: "그루트", age: 4, species: "플로라콜로서스")
let rocket: PetElement = PetElement(petName: "로켓", age: 4, species: "라쿤")
EncodedPetList.append(groot)
EncodedPetList.append(rocket)

JSON 형태로 인코딩 되기 전 Data 타입으로 한번 거쳐가게 된다.
인코딩은 디코딩과 반대로 JSONEncoder 를 사용한다.

let encoder = JSONEncoder()
let encodedData = try encoder.encode(EncodedPetList)

디코딩 할 때와 마찬가지로 Data 타입으로 나온다.
JSON은 형식만 지켜진 String 값이므로 String을 통해 json 형태로 바꿔줄 수 있다.
이 때 .utf8형식으로 인코딩을 지정해주어야 제대로 한글이 나올 수 있다.

let jsonString = String(data: encodedData, encoding: .utf8)

0개의 댓글