본문 바로가기

iOS/SwiftUI

[Swift] Codable로 JSON파싱하기 -확장-

앞서 기초편에서 간단하게 JSON을 파싱하는 법을 알았는데 확장편에서는 마주할 법한 상황을 가정하여 좀 더 자세하게 다뤄 볼 예정이다.

 

목차

1. Json에 null값이 들어 왔을 때

2. 아예 Key값이 안들어 왔을 때

3. Json안에 Object가 들어 있을 때

4. CordingKeys 사용해보기

 

 

Json에 null값이 들어 왔을 때

struct User: Codable {
    let name: String
    let age: Int
    let picture: String
    let isActive: Bool
}

우리는 기초편에서 User의 모델을 위와 같이 정의했다. 하지만 이 구조체는 모든 값이 유효할 때만 데이터를 성공적으로 파싱할 수 있다.

{
    "name": "이기회",
    "age": 77,
    "picture": null, // picture가 null로 들어왔다.
    "isActive": true,
}

예를들어 json이 위와같이 온다면

이런식의 valueNotFound에러를 마주하고 데이터를 화면에 못 보여주게된다.

이렇게 nullable한 값이 오는 것을 방지하기 위해서는 데이터의 값 타입에 optinal을 추가하여 유연하게 대처 할 수 있게한다.

struct User: Codable {
    let name: String
    let age: Int
    let picture: String? // nullable
    let isActive: Bool
}

// UI
Image(user.picture ?? "") // picture

물론 UI에서 nil값 처리를 해주어야한다.

 

 

아예 Key값이 안들어 왔을 때

위의 경우는 value가 null로 들어왔지만 이번에는 아예 key가 없을 경우이다.

실무에서는 레거시코드를 제거할 때 이런 이런 오류가 발생할 수 있다.

{
    "name": "이기회",
    // age가 사라졌다.
    "picture": null,
    "isActive": true,
}

json이 이런 식으로 들어온다면

위와 같은 keyNotFound 에러를 마주하게 된다.

이것도 역시 값 타입을 optinal로 바꾸어주면 해결된다.

struct User: Codable {
    let name: String
    let age: Int?
    let picture: String?
    let isActive: Bool
}

// UI
Text("\(user.age ?? 100)") // age

 

 

Json안에 Object가 들어 있을 때

{
    "name": "이기회",
    "picture": null,
    "isActive": true,
    "location": {
        "city": "Seoul",
        "country": "Korea",
        "coordinates": {
            "latitude": "31.7581",
            "longitude": "-58.1757"
        }
    }
}

이번에는 Json value안에 또 다른 Json이 있을 경우에 Model을 구현해보자

struct User: Codable {
    let name: String?
    let age: Int?
    let picture: String?
    let isActive: Bool?
    let location: Location? // Codable을 준수하는 구조체
}

struct Location: Codable {
    let city: String?
    let country: String?
    let coordinates: Coordinates? // Codable을 준수하는 구조체
}

struct Coordinates: Codable {
    let latitude: String?
    let longitude: String?
}

만들고자하는 Object를 새로 구조체를 만들어서 위와같이 사용하면 된다.

 

 

CordingKeys 사용해보기

지금까지는 Json의 key이름을 그대로 swift에서 사용했다. 하지만 그러고 싶지 않을 경우에는 어떻게 할까?

{
    "name": "이기회",
    "picture": null,
    "isActive": true,
    "location": {
        "city": "Seoul",
        "country": "Korea",
        "coordinates": {
            "latitude": "31.7581",
            "longitude": "-58.1757"
        }
    },
    "user_gender": "male"
}

Json key로 user_gender로 주었지만 Swift 변수명으로는 적합하지 않다.

struct User: Codable {
    let name: String?
    let age: Int?
    let picture: String?
    let isActive: Bool?
    let location: Location?
    let gender: String?
    
    enum CodingKeys: String, CodingKey {
        case name
        case age
        case picture
        case isActive
        case location
        case gender = "user_gender"
    }
}

이 경우에는 CodingKey를 준수하는 CodingKeys라는 열거형을 만듭니다. (단어 맨 뒤 s확인!!)

그 모델의 변수명을 그대로 case에 쓰고 파싱할 이름을 rawValue에 넣어 사용하면 됩니다.

그러면 위와 같이 gender에 male이 성공적으로 들어오는 것을 확인 할 수 있습니다.

 

 

실전 Tip.

이제 배운 것을 바탕으로 https://randomuser.me/api/의 Json을 파싱해보자

{
  "results": [
    {
      "gender": "male",
      "name": {
        "title": "mr",
        "first": "brad",
        "last": "gibson"
      },
      "location": {
        "street": "9278 new road",
        "city": "kilcoole",
        "state": "waterford",
        "postcode": "93027",
        "coordinates": {
          "latitude": "20.9267",
          "longitude": "-7.9310"
        },
        "timezone": {
          "offset": "-3:30",
          "description": "Newfoundland"
        }
      },
      "email": "brad.gibson@example.com",
      "login": {
        "uuid": "155e77ee-ba6d-486f-95ce-0e0c0fb4b919",
        "username": "silverswan131",
        "password": "firewall",
        "salt": "TQA1Gz7x",
        "md5": "dc523cb313b63dfe5be2140b0c05b3bc",
        "sha1": "7a4aa07d1bedcc6bcf4b7f8856643492c191540d",
        "sha256": "74364e96174afa7d17ee52dd2c9c7a4651fe1254f471a78bda0190135dcd3480"
      },
      "dob": {
        "date": "1993-07-20T09:44:18.674Z",
        "age": 26
      },
      "registered": {
        "date": "2002-05-21T10:59:49.966Z",
        "age": 17
      },
      "phone": "011-962-7516",
      "cell": "081-454-0666",
      "id": {
        "name": "PPS",
        "value": "0390511T"
      },
      "picture": {
        "large": "https://randomuser.me/api/portraits/men/75.jpg",
        "medium": "https://randomuser.me/api/portraits/med/men/75.jpg",
        "thumbnail": "https://randomuser.me/api/portraits/thumb/men/75.jpg"
      },
      "nat": "IE"
    }
  ],
  "info": {
    "seed": "fea8be3e64777240",
    "results": 1,
    "page": 1,
    "version": "1.3"
  }
}

이 API는 위와같이 Json을 내려준다고 한다. 이제 이것을 Swift 구조체로 만들어야 되는데 필요한 값만 쏙쏙 빼서 만들어도 되지만 Json을 struct로 바꿔주는 갓갓 퀵타입을 사용하자..!

result안에 있는 데이터만 복사해서 붙여넣기하면 이렇게 알아서 다 만들어준다

이것을 그대로 복사 붙여넣기하면된다