CodingKey프로토콜을 채택하는 열거형의 이름은 CodingKeys여야한다.

임혜정·2024년 7월 12일
2
post-custom-banner

1. 자동합성가능 (제일 큰 목적)

Codable 프로토콜은 CodingKeys라는 이름의 enum을 자동으로 찾아 사용한다. CodingKeys라는 이름을 사용하면 별도의 추가 코드 없이 자동으로 인코딩/디코딩이 가능해지게 설계되었다.

2. CodingKeys라는 이름을 사용해서 해당 enum의 목적이 Codable구현을 위한 것임을 빠르게 알아챌 수 있다.

3. 컴파일러가 이 이름을 인식하고 최적화된 코드를 생성할 수 있다.


https://github.com/swiftlang/swift/blob/main/lib/Sema/DerivedConformanceCodable.cpp

/// 열거형(case)의 CodingKey에 대한 식별자를 계산합니다.
static Identifier caseCodingKeysIdentifier(const ASTContext &C,
                                         EnumElementDecl *elt) {
  llvm::SmallString<16> scratch;
  camel_case::appendSentenceCase(scratch, elt->getBaseIdentifier().str());
  scratch += C.Id_CodingKeys.str();
  return C.getIdentifier(scratch.str());
}

/// \c target에 중첩된 \c CodingKeys 열거형을 가져옵니다. 
/// "CodingKeys" 엔티티가 타입 별칭(typealias)일 경우, 타입 별칭을 통해 접근할 수 있습니다.
///
/// 이는 오직 \c CodingKeys 열거형이 유효한지 확인되었을 때(즉, \c hasValidCodingKeysEnum를 통해) 
/// 또는 생성되었을 때(즉, \c synthesizeCodingKeysEnum를 통해)만 유용합니다.
///
/// \param C 조회를 수행할 \c ASTContext입니다.
///
/// \param target 조회할 대상 타입입니다.
///
/// \return \c target이 유효한 \c CodingKeys 열거형을 가지고 있다면 이를 반환합니다;
/// 그렇지 않다면 \c nullptr을 반환합니다.

위의 장점을 무시하고 CodingKeys라는 이름을 쓰지 않아야할 특별한 상황이 있을 경우, 코드가 많이 늘어나지만 가능은 하다.

상황: enum의 이름을 CodingKeys말고 AppleKey로 짓고싶다.

import Foundation

struct CurrentWeatherResult: Codable {
    let weather: [Weather]
    let main: WeatherMain
    
    enum AppleKeys: String, CodingKey {
        case weather
        case main
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: AppleKeys.self)
        weather = try container.decode([Weather].self, forKey: .weather)
        main = try container.decode(WeatherMain.self, forKey: .main)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: AppleKeys.self)
        try container.encode(weather, forKey: .weather)
        try container.encode(main, forKey: .main)
    }
}
// MARK: -----
struct Weather: Codable {
    let id: Int
    let main: String
    let description: String
    let icon: String
    
    enum AppleKeys: String, CodingKey {
        case id
        case main
        case description
        case icon
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: AppleKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        main = try container.decode(String.self, forKey: .main)
        description = try container.decode(String.self, forKey: .description)
        icon = try container.decode(String.self, forKey: .icon)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: AppleKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(main, forKey: .main)
        try container.encode(description, forKey: .description)
        try container.encode(icon, forKey: .icon)
    }
}

// MARK: -----
struct WeatherMain: Codable {
    let temp: Double
    let tempMin: Double
    let tempMax: Double
    let humidity: Int
    
    enum AppleKeys: String, CodingKey {
        case temp
        case tempMin = "temp_min"
        case tempMax = "temp_max"
        case humidity
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: AppleKeys.self)
        temp = try container.decode(Double.self, forKey: .temp)
        tempMin = try container.decode(Double.self, forKey: .tempMin)
        tempMax = try container.decode(Double.self, forKey: .tempMax)
        humidity = try container.decode(Int.self, forKey: .humidity)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: AppleKeys.self)
        try container.encode(temp, forKey: .temp)
        try container.encode(tempMin, forKey: .tempMin)
        try container.encode(tempMax, forKey: .tempMax)
        try container.encode(humidity, forKey: .humidity)
    }
}

// JSON 디코딩
let jsonData = """
{
    "weather": [
        {
            "id": 800,
            "main": "Clear",
            "description": "clear sky",
            "icon": "01d"
        }
    ],
    "main": {
        "temp": 293.55,
        "temp_min": 289.82,
        "temp_max": 295.37,
        "humidity": 36
    }
}
""".data(using: .utf8)!

do {
    let weatherResult = try JSONDecoder().decode(CurrentWeatherResult.self, from: jsonData)
    print(weatherResult)
} catch {
    print("Decoding error: \(error)")
}
profile
오늘 배운걸 까먹었을 미래의 나에게..⭐️
post-custom-banner

0개의 댓글