JSON → Swift Codable 변환기
JSON에서 Codable을 채택한 Swift struct를 생성하고, 디코딩을 위한 편의 이니셜라이저도 함께 제공합니다.
JSON에서 Swift Codable struct 생성
Codable은 Swift에서 JSON을 디코딩하는 표준 방식이지만, 큰 페이로드에 맞춰 모델 struct를 직접 작성하는 일은 번거롭습니다. 이 변환기는 객체마다 Codable을 채택한 struct를 생성하며, 속성은 Int, Double, String, Bool, 중첩 struct, 배열 타입의 let으로 선언됩니다. JSON 키가 Swift 속성 이름과 다르면 CodingKeys enum이 추가되고, Data·JSON String·URL에서 디코딩하는 이니셜라이저, 일부 값을 바꾼 복사본을 만드는 with(...) 메서드, 다시 인코딩하는 jsonData()/jsonString()을 담은 extension도 함께 생성됩니다.
사용 방법
- iOS나 macOS 앱이 받는 응답 같은 JSON 샘플을 붙여넣습니다.
- 루트 타입 이름을 입력합니다. 예: Article.
- 파일을 Xcode 프로젝트에 추가하고 try Article(jsonString) 또는 JSONDecoder().decode(Article.self, from: data)로 디코딩합니다.
자주 묻는 질문
- SwiftUI나 URLSession과 함께 사용할 수 있나요?
- 네. 생성된 struct는 일반적인 Codable 값 타입이므로 URLSession이 반환한 Data를 디코딩한 뒤 다른 모델처럼 SwiftUI 뷰에 전달하면 됩니다.
- snake_case 키는 어떻게 처리되나요?
- 속성은 Swift 스타일의 camelCase 이름을 갖고(is_featured는 isFeatured가 됨), CodingKeys enum이 각 속성을 원래 JSON 키에 매핑하므로 keyDecodingStrategy를 따로 설정할 필요가 없습니다.
- 편의 extension을 삭제해도 되나요?
- 네. Codable에 필요한 것은 struct 선언과 CodingKeys뿐입니다. extension과 newJSONDecoder/newJSONEncoder 헬퍼는 편의를 위한 선택 사항이므로 삭제해도 됩니다.
예시: JSON to Swift
입력 JSON
{
"id": 3,
"title": "Hello Swift",
"author": { "name": "Taylor", "followers": 1200 },
"is_featured": true
}생성된 Swift 코드 (Article)
// This file was generated from JSON Schema using quicktype, do not modify it directly.
// To parse the JSON, add this file to your project and do:
//
// let article = try Article(json)
import Foundation
// MARK: - Article
struct Article: Codable {
let id: Int
let title: String
let author: Author
let isFeatured: Bool
enum CodingKeys: String, CodingKey {
case id, title, author
case isFeatured = "is_featured"
}
}
// MARK: Article convenience initializers and mutators
extension Article {
init(data: Data) throws {
self = try newJSONDecoder().decode(Article.self, from: data)
}
init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
id: Int? = nil,
title: String? = nil,
author: Author? = nil,
isFeatured: Bool? = nil
) -> Article {
return Article(
id: id ?? self.id,
title: title ?? self.title,
author: author ?? self.author,
isFeatured: isFeatured ?? self.isFeatured
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Author
struct Author: Codable {
let name: String
let followers: Int
}
// MARK: Author convenience initializers and mutators
extension Author {
init(data: Data) throws {
self = try newJSONDecoder().decode(Author.self, from: data)
}
init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
name: String? = nil,
followers: Int? = nil
) -> Author {
return Author(
name: name ?? self.name,
followers: followers ?? self.followers
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Helper functions for creating encoders and decoders
func newJSONDecoder() -> JSONDecoder {
let decoder = JSONDecoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
decoder.dateDecodingStrategy = .iso8601
}
return decoder
}
func newJSONEncoder() -> JSONEncoder {
let encoder = JSONEncoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
encoder.dateEncodingStrategy = .iso8601
}
return encoder
}