Published on

๐ŸŽ Swift - Decoder์˜ Container

Authors
  • avatar
    Name
    ์ด์ฐฝ์ค€
    Twitter

๋ฐฐ๊ฒฝ

  • ๋ญ๋งŒ ํ•˜๋ฉด ๋””์ฝ”๋”ฉ ์—๋Ÿฌ!
    • ๋„ˆ๋ฌด ์˜ˆ๋ฏผ๋ณด์Šค์ธ Encodable๊ณผ Decodable

๊ณผ์ •

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ ์˜ˆ์ƒ์น˜ ๋ชป ํ•œ ์ธ์ฝ”๋”ฉ/๋””์ฝ”๋”ฉ ์—๋Ÿฌ๋“ค์„ ๋งˆ์ฃผ์ณค์Šต๋‹ˆ๋‹ค.

์–ด์„คํ”„๊ฒŒ ์•Œ๊ณ  ์žˆ๋˜ ์ง€์‹๋“ค๊ณผ ์‹ค์ˆ˜๋“ค์ด ๋ฌธ์ œ์˜€๋Š”๋ฐ์š”, ๋‹ค์‹œ๋Š” ์ด๋Ÿฐ ์ผ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋„๋ก ๋ฉ”๋ชจํ•ด๋‘๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

Container

let container = try decoder.singleValueContainer()
let coordinates = try container.decode([Double].self)

์ธ์ฝ”๋”ฉ๊ณผ ๋””์ฝ”๋”ฉ์„ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” Container.. ์ •ํ™•ํžˆ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•Œ๊ณ  ๊ณ„์‹ ๊ฐ€์š”?

์ €๋Š” ์ž˜ ๋ชฐ๋ผ์„œ ใ…Ž.. ์ด๋ฒˆ์— ํ•œ ๋ฒˆ ์•Œ์•„๋ดค์Šต๋‹ˆ๋‹ค.

// Data: [23.538399, -138.438982]
public init(from decoder: Decoder) throws {
	let container = try decoder.unkeyedContainer()
	let coordinates = try container.decode([Double].self)
	guard coordinates.count == 2 else {
		throw DecodingError.dataCorruptedError(in: container,
												   debugDescription: "Coordinate ๊ฐ’์€ 2๊ฐœ ๊ฐ’์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฐฐ์—ด์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
	}
	self.latitude = coordinates[0]
	self.longitude = coordinates[1]
}

์ฐธ๊ณ ๋กœ ๋ฌธ์ œ๊ฐ€ ๋๋˜ ์ฝ”๋“œ๋Š” ์œ„ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

์–ด๋–ค ๋ถ€๋ถ„์ด ๋ฌธ์ œ์ธ์ง€ ๋ชจ๋ฅด์‹œ๊ฒ ๋‹ค๋ฉด.. ๋”ฐ๋ผ์˜ค์‹œ์ฃ .

KeyedDecodingContainer

CodingKey๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

// Data:
// {
//   "name": "S045 ์ด์ฐฝ์ค€"
//   "id": "1D723110-BD79-4839-9A30-1629BF49CFE8"
// }

struct SomeData: Decodable {
	var name: String?
	let id: UUID

	enum CodingKeys: String, CodingKey {
	case name = "title"
	case id = "_id"
	}
}

CodingKey ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜๋Š” ์—ด๊ฑฐํ˜•์„ ๋งŒ๋“ค์–ด ๋งค์นญ์‹œ์ผœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

init(from decoder: Decoder) throws {
	let container = try decoder.container(keyedBy: CodingKeys.self)
	self.name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
	self.id = try container.decode(UUID.self, forKey: .id)
}

์ผ๋ฐ˜์ ์œผ๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ์‹์ด๊ณ , ์ € ๋˜ํ•œ ์ต์ˆ™ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

SingleValueContainer

๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ๋˜ SingleValueContainer์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์‚ฌ์‹ค, ์ž˜ ์•Œ๊ณ  ์žˆ์œผ๋ฉด ์ด๊ฑฐ๋งŒํผ ๊ฐ„๋‹จํ•œ ๊ฒƒ๋„ ์—†์Šต๋‹ˆ๋‹ค.

๋ง ๊ทธ๋Œ€๋กœ ๋‹จ์ˆœํžˆ ํ•˜๋‚˜์˜ ๊ฐ’๋งŒ ๋ก ๋“ค์–ด์™”์„ ๋•Œ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

// Data: "S045 ์ด์ฐฝ์ค€"

struct OneData: Decodable {
	let name: String

	init(from decoder: Decoder) throws {
		let container = try decoder.singleValueContainer()
		self.name = try container.decode(String.self)
	}
}

๋„ค.. ์•Œ๊ณ ๋ณด๋‹ˆ๊นŒ ์ฐธ ์‰ฝ์ฃ ..

UnkeyedContainer

UnkeyedContainer ๊ฐ™์€ ๊ฒฝ์šฐ๊ฐ€ ์กฐ๊ธˆ ํ—ท๊ฐˆ๋ฆฌ๋ฉด์„œ๋„ ํŠน์ดํ•ฉ๋‹ˆ๋‹ค.

๋ฐฐ์—ด๋กœ ๊ฐ’์ด ๋“ค์–ด์˜ค๋Š”๋ฐ, ๊ทธ ํƒ€์ž…๋“ค์ด ์ œ๊ฐ๊ฐ์ผ ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

// Data: ["S045 ์ด์ฐฝ์ค€", 0.45, true, 28]

struct UnkeyedData: Decodable {
	var name: String?
	var id: Double?
	var isCheckedIn: Bool?
	var age: Int?

	init(from decoder: Decoder) throws {
		var container = try decoder.unkeyedContainer()
		self.name = try container.decode(String?.self)
		self.id = try container.decode(Double?.self)
		self.isCheckedIn = try container.decode(Bool?.self)
		self.age = try container.decode(Int?.self)
	}
}

๋ฐฐ์—ด ์•ˆ์— ์—ฌ๋Ÿฌ ํƒ€์ž…๋“ค์ด ์žˆ์ง€๋งŒ, ํ”„๋กœํผํ‹ฐ ์ˆœ์„œ๋Œ€๋กœ ๋งค์นญํ•ด ๋””์ฝ”๋”ฉํ•ด์ค๋‹ˆ๋‹ค.

์—๋Ÿฌ ํ•ด๊ฒฐ

// Data: [23.538399, -138.438982]
public init(from decoder: Decoder) throws {
	let container = try decoder.unkeyedContainer()
	let coordinates = try container.decode([Double].self)
	guard coordinates.count == 2 else {
		throw DecodingError.dataCorruptedError(in: container,
												   debugDescription: "Coordinate ๊ฐ’์€ 2๊ฐœ ๊ฐ’์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฐฐ์—ด์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
	}
	self.latitude = coordinates[0]
	self.longitude = coordinates[1]
}

๊ทธ๋Ÿผ ๋Œ์•„๊ฐ€์„œ ์ด ์ฝ”๋“œ๋Š” ๋ญ๊ฐ€ ๋ฌธ์ œ์˜€์„๊นŒ์š”?

๋ฐฉ์‹์€ singleValueContainer ๋ฐฉ์‹์„ ์“ฐ๊ณ  ์žˆ์ง€๋งŒ, unkeyedContainer๋ฅผ ์“ฐ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

UnkeyedContainer๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๊ฒ ์ฃ .

// Data: [23.538399, -138.438982]
public init(from decoder: Decoder) throws {
	var container = try decoder.unkeyedContainer()
	self.latitude = try container.decode(Double.self)
	self.longitude = try contianer.decode(Double.self)
}

์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์—ˆ์„ ๊ฒ๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ

์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋˜ decode ๋ฐฉ์‹์— ๋Œ€ํ•ด ์ด๋ฒˆ ๊ธฐํšŒ์— ๋‹ค์‹œ ์•Œ์•„๋ดค์Šต๋‹ˆ๋‹ค.

๊ทธ๋ƒฅ ๋Š๋‚Œ๋Œ€๋กœ ์“ฐ๋˜ ๋Š๋‚Œ์ด ์žˆ์—ˆ๋Š”๋ฐ ์ง€๊ธˆ์ด๋ผ๋„ ์•Œ์•„๋ณด๊ฒŒ ๋˜์–ด์„œ ๋‹คํ–‰์ด๋„ค์š”.

ํ˜„์—…์— ๊ฐ€๋ฉด ์ด ๋ฌธ์ œ๊ฐ€ ์ƒ๋‹นํžˆ ํด ๊ฒƒ ๊ฐ™์€๋ฐ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ์ง€๋„ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ  ๋ฌธ์„œ