개발/Swift

Swift 데이터 감싸져 있는 안에 있는 값 꺼내서 Decode하기

덤벨로퍼 2023. 7. 22. 16:07

 

{
    "identifier": "dsdfdsf",
    "name": "james",
    "product: {
		"expiration_poloicy": {
			"expire" : 90 
		}	
	}
}

위와 같은 데이터를 서버로부터 받을때

원하는 데이터인 expire는 두번 감싸져 있다.

해당 데이터를 decoding을 하기위해 Entity를 총 세개나 만들어야 원하는 데이터값을 받을수 있을것이다.

struct People: Decodable {
var identifier: String
var name: String
var product: Product
}

struct Product: Decodable {
var expirationPlicy: ExpirationPlicy
	//public init(from decoder: Decoder) throws {} ....
}

struct ExpirationPlicy: Decodable {
var expire: Int
	//public init(from decoder: Decoder) throws {} ....
}

이렇게 가능하다

하지만 만약 이렇게 엔티티를 여러개 만들고 싶지않고 People 인스턴스안에 expire 데이터를 넣고싶다면

코딩키와 nestedContainer를 사용해 가능하다

struct People: Decodable {
var identifier: String
var name: String
var expire: Int
enum CodingKeys: String, CodingKey {
        case identifier
        case name
        case product
        enum Product: String, CodingKey {
            case expirationPolicy = "expiration_policy"
            enum ExpirationPolicy: String, CodingKey {
                case expire
            }
        }
    }
}

코딩키 안에 Product 와 ExpirationPolicy코딩키를 또 만들어주었다.

이제 디코딩을 하려면 nestedContainer 를 사용하면 되는데

	
let container = try decoder.container(keyedBy: CodingKeys.self)

let productContainer = try container.nestedContainer(keyedBy: CodingKeys.Product.self,
                                                                   forKey: .product)
	

nestedContainer 를 통해 Product container를 생성 할수 있다.

이러면 이 컨테이너를 통해 컨테이너 안에 expirationPolicy에 접근 할수 있다.

let expirationPolicyContainer = try productContainer
            .nestedContainer(keyedBy: CodingKeys.Product.ExpirationPolicy.self,
                             forKey: .expirationPolicy)

역시 ExpirationPolicy 안에 접근해야 하기 때문에 똑같이 컨테이너를 생성해주고

self.expire = try expirationPolicyContainer.decode(Int.self, forKey: .expire)

expire 에 결국 접근할수 있게 되었다.

public init(from decoder: Decoder) throws {
	let container = try decoder.container(keyedBy: CodingKeys.self)
	self.identifier = try container.decode(String.self, forKey: .identifier)
	self.name = try container.decode(String.self, forKey: .name)
	let productContainer = try container.nestedContainer(keyedBy: CodingKeys.Product.self,
	                                                                   forKey: .product)
	let expirationPolicyContainer = try productContainer
	            .nestedContainer(keyedBy: CodingKeys.Product.ExpirationPolicy.self,
	                             forKey: .expirationPolicy)
	self.expire = try expirationPolicyContainer.decode(Int.self, forKey: .expire)
}

전체 코드