跳至內容

JSON 轉 Swift

從 JSON 範例生成符合 Codable 的 Swift struct。

輸入

這個工具的用途

從 JSON 樣本產生符合 Codable Swift struct。屬性以 let 宣告為 Swift 慣用型別;樣本中為 null 的欄位成為 Optional。 若 JSON 鍵碰到 Swift 保留字(publicclass), 會以反引號逸出。底層使用 quicktype,完全在你的瀏覽器內運作。

使用步驟

貼上 JSON(或載入範例),即可在右側讀到 Swift struct。每個巢狀物件 成為各自的 Codable struct;當 JSON 鍵與 Swift 屬性名相符 時,輸出可直接給 Foundation 的 JSONDecoder 使用, 無需額外註解。

輸入: {"id":42,"name":"devsmiths","createdAt":"2024-03-11T08:24:00Z","stars":1280,"public":true,"contributors":[{"login":"ada","commits":51,"admin":true},{"login":"linus","commits":33,"admin":false}],"homepage":null}

輸出(Swift):

import Foundation

struct Root: Codable {
    let id: Int
    let name: String
    let createdAt: String
    let stars: Int
    let `public`: Bool
    let contributors: [Contributor]
    let homepage: String?
}

struct Contributor: Codable {
    let login: String
    let commits: Int
    let admin: Bool
}

限制與邊界情況

  • 輸出採 struct 並符合 Codable, 不是 class。struct 是 Swift 的 value type—— 適合 JSON DTO。若需要 reference 語意(例如 SwiftUI 的 @ObservableObject),請手動以 class 包裹。
  • 屬性為 let(不可變)。需要修改時透過 var copy = original 重建,或手動把真的會被修改的欄位 改為 var
  • Swift 保留字(publicclass default)作為 JSON 鍵時,會在 Swift 原始碼中以反引號 包覆(let `public`: Bool);JSONDecoder 看到的是原始鍵。
  • camelCase / snake_case 不一致:預設不產生 CodingKeys enum,因此 JSON 鍵必須與 Swift 屬性名字元對字元相符。snake_case JSON 請設定 decoder.keyDecodingStrategy = .convertFromSnakeCase, 不必為每個 struct 顯式產生 CodingKeys
  • 日期字串保持為 String。請設定 decoder.dateDecodingStrategy = .iso8601 並手動把屬性 改為 Date——JSONDecoder 沒有 per-field 日期策略。
  • 單樣本推論:樣本中不存在的鍵不會自動變 Optional。 切換 all optional 套用全部欄位。

常見問題

為什麼是 struct + Codable 而不是 class?
struct 是 Swift 的 value type,作為 JSON DTO 完全合適——複製語意、無 reference cycle、建構上是 thread-safe。Codable 是 stdlib protocol(Encodable + Decodable),JSONDecoder / JSONEncoder 都對它操作。需要 reference 語意時(SwiftUI 的 @ObservedObject、持久化),請手動以 class 包裹 struct 或在 wrapper 上使用 @Observable。
如何處理 camelCase JSON vs snake_case JSON 鍵?
JSONDecoder 有 `keyDecodingStrategy`。snake_case JSON:`decoder.keyDecodingStrategy = .convertFromSnakeCase`。產生的 struct 使用 camelCase 屬性名(Swift 慣例);策略自動架橋。若大小寫混雜或鍵不遵循任一慣例,請為各 struct 顯式產生 `CodingKeys` enum——產生器預設不這麼做,因為全域策略通常已足夠。
Date 欄位可以變成 Date 而非 String 嗎?
可以,兩步。把產生的 struct 中的 String 改為 Date,設定 `decoder.dateDecodingStrategy = .iso8601`(或 `.formatted(...)` 處理非 ISO 格式)。dateDecodingStrategy 是 decoder 全域——每個 Date 屬性都同等對待。若需要 per-field 控制,寫自訂 `init(from:)` 個別處理每個 Date 欄位。
為什麼我的 JSON 鍵 public 被反引號包覆?
因為 `public` 是 Swift 存取修飾字。反引號讓你可以把保留字當識別字使用(`let `public`: Bool`)而不必重新命名。JSONDecoder 看到原始鍵(`public`)並繫結到被反引號包覆的 Swift 屬性。若偏好重新命名,加 `CodingKeys` enum:`case isPublic = "public"`,使用 `isPublic` 作為 Swift 端名稱。
完全不是合法 Swift 識別字的 JSON 鍵怎麼辦?
含連字號或開頭為數字的鍵(`2024-tax-year`)即使加反引號也無法當 Swift 屬性名。請使用顯式 `CodingKeys` enum:`case taxYear = "2024-tax-year"`,以 `taxYear` 作為 Swift 端名稱。當 JSON 鍵在任何逸出下都不合法時,產生器會自動輸出 CodingKeys enum。
產生的 struct 可以配 SwiftData / Core Data 使用嗎?
不能直接配。兩個框架都要 `@Model`(SwiftData)或 `NSManagedObject`(Core Data)基底類別——這是帶持久化機制的 reference type。產生的 struct 是純 value type。請將其作為 DTO 層使用(解析 JSON → struct → 傳給映射函式 → 寫入 SwiftData model)。單向映射讓解析層快、持久化層意圖明確。

內容審閱者: