본문 바로가기
프로그래밍 팁/Swift

Swift에서 Codable 객체와 딕셔너리(Dictionary)를 상호 변환하는 방법

by Archivers 2020. 11. 18.

 

 

Encodable → 딕셔너리

Encodable 혹은 Codable을 따르는 객체를 딕셔너리 타입으로 변환하는 방법은 다음과 같습니다. 우선 extension부터 정의합니다.

extension Encodable {
    func encode() throws -> [String: Any] {
        let data = try JSONEncoder().encode(self)
        guard let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else {
            throw NSError()
        }

        return dictionary
    }
}

1. JSONEncoder를 사용해서 Encodable을 따르는 객체를 JSON 데이터로 변환하고

2. JSONSerialization을 통해 JSON 오브젝트로 변환한 뒤 [String: Any]라는 딕셔너리 타입으로 캐스팅합니다. 이 때 throw NSError() 자리에는 미리 정의해둔 Error 케이스로 교체하시면 됩니다.

위의 extension을 사용하는 방법은 다음과 같습니다.

do {
    let dictionary = try object.encode()
    // dictionary 사용
} catch {
    // 에러 처리
    print(error)
}

이 때, object라는 객체는 Encodable 혹은 Codable을 따르는 객체입니다.

 

딕셔너리 → Decodable

이번에는 반대로 딕셔너리 타입의 모델을 Decodable 객체로 변환하는 방법에 대해 설명하겠습니다. 정의하게 될 extension은 다음과 같습니다.

extension Decodable {
    static func decode<T: Decodable>(dictionary: [String: Any]) throws -> T {
        let data = try JSONSerialization.data(withJSONObject: dictionary, options: [.fragmentsAllowed])
        return try JSONDecoder().decode(T.self, from: data)
    }
}

1. JSONSerialization을 통해 딕셔너리를 Data 타입으로 변환합니다.

2. JSONDecoder를 통해 해당 Data 객체를 decode합니다.

위의 extension을 사용하는 방법은 다음과 같습니다.

do {
    let object: Archive = try Archive.decode(dictionary: dictionary)
    // object 사용
} catch {
    // 에러 처리
    print(error)
}

여기서 예시로 사용한 ArchiveDecodable 혹은 Codable을 따르는 클래스 혹은 구조체입니다. 한 가지 팁은, 위처럼 객체를 선언하는 방식으로 사용한다면 let object: Archive = ...의 형식으로 선언해 줘야 타입 유추 시 에러가 나지 않는다는 것입니다.

댓글