{"id":"447e3fa7-e97b-4389-a876-439ef5cdc718","shortId":"gjB88n","kind":"skill","title":"Swift Codable","tagline":"Swift Ios Skills skill by Dpearson2699","description":"# Swift Codable\n\nEncode and decode Swift types using `Codable` (`Encodable & Decodable`) with\n`JSONEncoder`, `JSONDecoder`, and related APIs. Targets Swift 6.3 / iOS 26+.\n\n## Contents\n\n- [Basic Conformance](#basic-conformance)\n- [Custom CodingKeys](#custom-codingkeys)\n- [Custom Decoding and Encoding](#custom-decoding-and-encoding)\n- [Nested and Flattened Containers](#nested-and-flattened-containers)\n- [Heterogeneous Arrays](#heterogeneous-arrays)\n- [Date Decoding Strategies](#date-decoding-strategies)\n- [Data and Key Strategies](#data-and-key-strategies)\n- [Lossy Array Decoding](#lossy-array-decoding)\n- [Single Value Containers](#single-value-containers)\n- [Default Values for Missing Keys](#default-values-for-missing-keys)\n- [Encoder and Decoder Configuration](#encoder-and-decoder-configuration)\n- [Codable with URLSession](#codable-with-urlsession)\n- [Codable with SwiftData](#codable-with-swiftdata)\n- [Codable with UserDefaults](#codable-with-userdefaults)\n- [Common Mistakes](#common-mistakes)\n- [Review Checklist](#review-checklist)\n- [References](#references)\n\n## Basic Conformance\n\nWhen all stored properties are themselves `Codable`, the compiler synthesizes\nconformance automatically:\n\n```swift\nstruct User: Codable {\n    let id: Int\n    let name: String\n    let email: String\n    let isVerified: Bool\n}\n\nlet user = try JSONDecoder().decode(User.self, from: jsonData)\nlet encoded = try JSONEncoder().encode(user)\n```\n\nPrefer `Decodable` for read-only API responses and `Encodable` for write-only.\nUse `Codable` only when both directions are required.\n\n## Custom CodingKeys\n\nRename JSON keys without writing a custom decoder by declaring a `CodingKeys`\nenum:\n\n```swift\nstruct Product: Codable {\n    let id: Int\n    let displayName: String\n    let imageURL: URL\n    let priceInCents: Int\n\n    enum CodingKeys: String, CodingKey {\n        case id\n        case displayName = \"display_name\"\n        case imageURL = \"image_url\"\n        case priceInCents = \"price_in_cents\"\n    }\n}\n```\n\nEvery stored property must appear in the enum. Omitting a property from\n`CodingKeys` excludes it from encoding/decoding -- provide a default value or\ncompute it separately.\n\n## Custom Decoding and Encoding\n\nOverride `init(from:)` and `encode(to:)` for transformations the synthesized\nconformance cannot handle:\n\n```swift\nstruct Event: Codable {\n    let name: String\n    let timestamp: Date\n    let tags: [String]\n\n    enum CodingKeys: String, CodingKey {\n        case name, timestamp, tags\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n        name = try container.decode(String.self, forKey: .name)\n        // Decode Unix timestamp as Double, convert to Date\n        let epoch = try container.decode(Double.self, forKey: .timestamp)\n        timestamp = Date(timeIntervalSince1970: epoch)\n        // Default to empty array when key is missing\n        tags = try container.decodeIfPresent([String].self, forKey: .tags) ?? []\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encode(name, forKey: .name)\n        try container.encode(timestamp.timeIntervalSince1970, forKey: .timestamp)\n        try container.encode(tags, forKey: .tags)\n    }\n}\n```\n\n## Nested and Flattened Containers\n\nUse `nestedContainer(keyedBy:forKey:)` to navigate and flatten nested JSON:\n\n```swift\n// JSON: { \"id\": 1, \"location\": { \"lat\": 37.7749, \"lng\": -122.4194 } }\nstruct Place: Decodable {\n    let id: Int\n    let latitude: Double\n    let longitude: Double\n\n    enum CodingKeys: String, CodingKey { case id, location }\n    enum LocationKeys: String, CodingKey { case lat, lng }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n        id = try container.decode(Int.self, forKey: .id)\n        let location = try container.nestedContainer(\n            keyedBy: LocationKeys.self, forKey: .location)\n        latitude = try location.decode(Double.self, forKey: .lat)\n        longitude = try location.decode(Double.self, forKey: .lng)\n    }\n}\n```\n\nChain multiple `nestedContainer` calls to flatten deeply nested structures.\nAlso use `nestedUnkeyedContainer(forKey:)` for nested arrays.\n\n## Heterogeneous Arrays\n\nDecode arrays of mixed types using a discriminator field:\n\n```swift\n// JSON: [{\"type\":\"text\",\"content\":\"Hello\"},{\"type\":\"image\",\"url\":\"pic.jpg\"}]\nenum ContentBlock: Decodable {\n    case text(String)\n    case image(URL)\n\n    enum CodingKeys: String, CodingKey { case type, content, url }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n        let type = try container.decode(String.self, forKey: .type)\n        switch type {\n        case \"text\":\n            let content = try container.decode(String.self, forKey: .content)\n            self = .text(content)\n        case \"image\":\n            let url = try container.decode(URL.self, forKey: .url)\n            self = .image(url)\n        default:\n            throw DecodingError.dataCorruptedError(\n                forKey: .type, in: container,\n                debugDescription: \"Unknown type: \\(type)\")\n        }\n    }\n}\n\nlet blocks = try JSONDecoder().decode([ContentBlock].self, from: jsonData)\n```\n\n## Date Decoding Strategies\n\nConfigure `JSONDecoder.dateDecodingStrategy` to match your API:\n\n```swift\nlet decoder = JSONDecoder()\n\n// ISO 8601 (e.g., \"2024-03-15T10:30:00Z\")\ndecoder.dateDecodingStrategy = .iso8601\n\n// Unix timestamp in seconds (e.g., 1710499800)\ndecoder.dateDecodingStrategy = .secondsSince1970\n\n// Custom DateFormatter\nlet formatter = DateFormatter()\nformatter.dateFormat = \"yyyy-MM-dd\"\nformatter.locale = Locale(identifier: \"en_US_POSIX\")\nformatter.timeZone = TimeZone(secondsFromGMT: 0)\ndecoder.dateDecodingStrategy = .formatted(formatter)\n\n// Custom closure for multiple formats\ndecoder.dateDecodingStrategy = .custom { decoder in\n    let container = try decoder.singleValueContainer()\n    let string = try container.decode(String.self)\n    if let date = ISO8601DateFormatter().date(from: string) { return date }\n    throw DecodingError.dataCorruptedError(\n        in: container, debugDescription: \"Cannot decode date: \\(string)\")\n}\n```\n\nSet the matching strategy on `JSONEncoder`:\n`encoder.dateEncodingStrategy = .iso8601`\n\n## Data and Key Strategies\n\n```swift\nlet decoder = JSONDecoder()\ndecoder.dataDecodingStrategy = .base64           // Base64-encoded Data fields\ndecoder.keyDecodingStrategy = .convertFromSnakeCase  // snake_case -> camelCase\n// {\"user_name\": \"Alice\"} maps to `var userName: String` -- no CodingKeys needed\n\nlet encoder = JSONEncoder()\nencoder.dataEncodingStrategy = .base64\nencoder.keyEncodingStrategy = .convertToSnakeCase\n```\n\n## Lossy Array Decoding\n\nBy default, one invalid element fails the entire array. Use a wrapper to skip\ninvalid elements:\n\n```swift\nstruct LossyArray<Element: Decodable>: Decodable {\n    let elements: [Element]\n\n    init(from decoder: Decoder) throws {\n        var container = try decoder.unkeyedContainer()\n        var elements: [Element] = []\n        while !container.isAtEnd {\n            if let element = try? container.decode(Element.self) {\n                elements.append(element)\n            } else {\n                _ = try? container.decode(AnyCodableValue.self) // advance past bad element\n            }\n        }\n        self.elements = elements\n    }\n}\nprivate struct AnyCodableValue: Decodable {}\n```\n\n## Single Value Containers\n\nWrap primitives for type safety using `singleValueContainer()`:\n\n```swift\nstruct UserID: Codable, Hashable {\n    let rawValue: String\n\n    init(_ rawValue: String) { self.rawValue = rawValue }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n        rawValue = try container.decode(String.self)\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n        try container.encode(rawValue)\n    }\n}\n// JSON: \"usr_abc123\" decodes directly to UserID\n```\n\n## Default Values for Missing Keys\n\nUse `decodeIfPresent` with nil-coalescing to provide defaults:\n\n```swift\nstruct Settings: Decodable {\n    let theme: String\n    let fontSize: Int\n    let notificationsEnabled: Bool\n\n    enum CodingKeys: String, CodingKey {\n        case theme, fontSize = \"font_size\"\n        case notificationsEnabled = \"notifications_enabled\"\n    }\n\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: CodingKeys.self)\n        theme = try container.decodeIfPresent(String.self, forKey: .theme) ?? \"system\"\n        fontSize = try container.decodeIfPresent(Int.self, forKey: .fontSize) ?? 16\n        notificationsEnabled = try container.decodeIfPresent(\n            Bool.self, forKey: .notificationsEnabled) ?? true\n    }\n}\n```\n\n## Encoder and Decoder Configuration\n\n```swift\nlet encoder = JSONEncoder()\nencoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes]\n\n// Non-conforming floats (NaN, Infinity are not valid JSON)\nencoder.nonConformingFloatEncodingStrategy = .convertToString(\n    positiveInfinity: \"Infinity\", negativeInfinity: \"-Infinity\", nan: \"NaN\")\ndecoder.nonConformingFloatDecodingStrategy = .convertFromString(\n    positiveInfinity: \"Infinity\", negativeInfinity: \"-Infinity\", nan: \"NaN\")\n```\n\n### PropertyListEncoder / PropertyListDecoder\n\n```swift\nlet plistEncoder = PropertyListEncoder()\nplistEncoder.outputFormat = .xml  // or .binary\nlet data = try plistEncoder.encode(settings)\nlet decoded = try PropertyListDecoder().decode(Settings.self, from: data)\n```\n\n## Codable with URLSession\n\n```swift\nfunc fetchUser(id: Int) async throws -> User {\n    let url = URL(string: \"https://api.example.com/users/\\(id)\")!\n    let (data, response) = try await URLSession.shared.data(from: url)\n    guard let http = response as? HTTPURLResponse,\n          (200...299).contains(http.statusCode) else {\n        throw APIError.invalidResponse\n    }\n    let decoder = JSONDecoder()\n    decoder.keyDecodingStrategy = .convertFromSnakeCase\n    decoder.dateDecodingStrategy = .iso8601\n    return try decoder.decode(User.self, from: data)\n}\n\n// Generic API envelope for wrapped responses\nstruct APIResponse<T: Decodable>: Decodable {\n    let data: T\n    let meta: Meta?\n    struct Meta: Decodable { let page: Int; let totalPages: Int }\n}\nlet users = try decoder.decode(APIResponse<[User]>.self, from: data).data\n```\n\n## Codable with SwiftData\n\n`Codable` structs work as composite attributes in SwiftData models. In iOS 18+,\nSwiftData natively supports them without explicit `@Attribute(.transformable)`:\n\n```swift\nstruct Address: Codable {\n    var street: String\n    var city: String\n    var zipCode: String\n}\n\n@Model class Contact {\n    var name: String\n    var address: Address?  // Codable struct stored as composite attribute\n    init(name: String, address: Address? = nil) {\n        self.name = name; self.address = address\n    }\n}\n```\n\n## Codable with UserDefaults\n\nStore `Codable` values via `RawRepresentable` for `@AppStorage`:\n\n```swift\nstruct UserPreferences: Codable {\n    var showOnboarding: Bool = true\n    var accentColor: String = \"blue\"\n}\n\nextension UserPreferences: RawRepresentable {\n    init?(rawValue: String) {\n        guard let data = rawValue.data(using: .utf8),\n              let decoded = try? JSONDecoder().decode(Self.self, from: data)\n        else { return nil }\n        self = decoded\n    }\n    var rawValue: String {\n        guard let data = try? JSONEncoder().encode(self),\n              let string = String(data: data, encoding: .utf8)\n        else { return \"{}\" }\n        return string\n    }\n}\n\nstruct SettingsView: View {\n    @AppStorage(\"userPrefs\") private var prefs = UserPreferences()\n    var body: some View {\n        Toggle(\"Show Onboarding\", isOn: $prefs.showOnboarding)\n    }\n}\n```\n\n## Common Mistakes\n\n**1. Not handling missing optional keys:**\n```swift\n// DON'T -- crashes if key is absent\nlet value = try container.decode(String.self, forKey: .bio)\n// DO -- returns nil for missing keys\nlet value = try container.decodeIfPresent(String.self, forKey: .bio) ?? \"\"\n```\n\n**2. Failing entire array when one element is invalid:**\n```swift\n// DON'T -- one bad element kills the whole decode\nlet items = try container.decode([Item].self, forKey: .items)\n// DO -- use LossyArray or decode elements individually\nlet items = try container.decode(LossyArray<Item>.self, forKey: .items).elements\n```\n\n**3. Date strategy mismatch:**\n```swift\n// DON'T -- default strategy expects Double, but API sends ISO string\nlet decoder = JSONDecoder()  // dateDecodingStrategy defaults to .deferredToDate\n// DO -- set strategy to match your API format\ndecoder.dateDecodingStrategy = .iso8601\n```\n\n**4. Force-unwrapping decoded optionals:**\n```swift\n// DON'T\nlet user = try? decoder.decode(User.self, from: data)\nprint(user!.name)\n// DO\nguard let user = try? decoder.decode(User.self, from: data) else { return }\n```\n\n**5. Using Codable when only Decodable is needed:**\n```swift\n// DON'T -- unnecessarily constrains the type to also be Encodable\nstruct APIResponse: Codable { let id: Int; let message: String }\n// DO -- use Decodable for read-only API responses\nstruct APIResponse: Decodable { let id: Int; let message: String }\n```\n\n**6. Manual CodingKeys for simple snake_case APIs:**\n```swift\n// DON'T -- verbose boilerplate for every model\nenum CodingKeys: String, CodingKey {\n    case userName = \"user_name\"\n    case avatarUrl = \"avatar_url\"\n}\n// DO -- configure once on the decoder\ndecoder.keyDecodingStrategy = .convertFromSnakeCase\n```\n\n## Review Checklist\n\n- [ ] Types conform to `Decodable` only when encoding is not needed\n- [ ] `decodeIfPresent` used with defaults for optional or missing keys\n- [ ] `keyDecodingStrategy = .convertFromSnakeCase` used instead of manual CodingKeys for simple snake_case APIs\n- [ ] `dateDecodingStrategy` matches the API date format\n- [ ] Arrays of unreliable data use lossy decoding to skip invalid elements\n- [ ] Custom `init(from:)` validates and transforms data instead of post-decode fixups\n- [ ] `JSONEncoder.outputFormatting` includes `.sortedKeys` for deterministic test output\n- [ ] Wrapper types (UserID, etc.) use `singleValueContainer` for clean JSON\n- [ ] Generic `APIResponse<T>` wrapper used for consistent API envelope handling\n- [ ] No force-unwrapping of decoded values\n- [ ] `@AppStorage` Codable types conform to `RawRepresentable`\n- [ ] SwiftData composite attributes use `Codable` structs\n\n## References\n\n- [Codable](https://sosumi.ai/documentation/swift/codable/) -- protocol combining Encodable and Decodable\n- [JSONDecoder](https://sosumi.ai/documentation/foundation/jsondecoder/) -- decodes JSON data into Codable types\n- [JSONEncoder](https://sosumi.ai/documentation/foundation/jsonencoder/) -- encodes Codable types as JSON data\n- [CodingKey](https://sosumi.ai/documentation/swift/codingkey/) -- protocol for encoding/decoding keys\n- [Encoding and Decoding Custom Types](https://sosumi.ai/documentation/foundation/encoding-and-decoding-custom-types/) -- Apple guide on custom Codable conformance\n- [Using JSON with Custom Types](https://sosumi.ai/documentation/foundation/archives_and_serialization/using_json_with_custom_types/) -- Apple sample code for JSON patterns","tags":["swift","codable","ios","skills","dpearson2699"],"capabilities":["skill","source-dpearson2699","category-swift-ios-skills"],"categories":["swift-ios-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/dpearson2699/swift-ios-skills/swift-codable","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"install_from":"skills.sh"}},"qualityScore":"0.300","qualityRationale":"deterministic score 0.30 from registry signals: · indexed on skills.sh · published under dpearson2699/swift-ios-skills","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T03:40:39.261Z","embedding":null,"createdAt":"2026-04-18T20:37:20.925Z","updatedAt":"2026-04-22T03:40:39.261Z","lastSeenAt":"2026-04-22T03:40:39.261Z","tsv":"'-03':625 '-122.4194':426 '-15':626 '/documentation/foundation/archives_and_serialization/using_json_with_custom_types/)':1619 '/documentation/foundation/encoding-and-decoding-custom-types/)':1605 '/documentation/foundation/jsondecoder/)':1573 '/documentation/foundation/jsonencoder/)':1583 '/documentation/swift/codable/)':1564 '/documentation/swift/codingkey/)':1593 '/users/':1012 '0':659 '00z':629 '1':421,1231 '16':926 '1710499800':637 '18':1096 '2':1265 '200':1028 '2024':624 '26':30 '299':1029 '3':1308 '30':628 '37.7749':424 '4':1341 '5':1371 '6':1417 '6.3':28 '8601':622 'abc123':857 'absent':1244 'accentcolor':1162 'address':1107,1125,1126,1136,1137,1142 'advanc':797 'alic':729 'also':499,1387 'anycodablevalu':805 'anycodablevalue.self':796 'api':25,198,616,1049,1320,1337,1406,1424,1485,1489,1538 'api.example.com':1011 'api.example.com/users/':1010 'apierror.invalidresponse':1034 'apirespons':1055,1076,1391,1409,1533 'appear':268 'appl':1606,1620 'appstorag':1152,1214,1548 'array':61,64,82,86,366,505,507,509,746,756,1268,1492 'async':1003 'attribut':1090,1103,1132,1556 'automat':161 'avatar':1443 'avatarurl':1442 'await':1018 'bad':799,1278 'base64':716,718,742 'base64-encoded':717 'basic':32,35,148 'basic-conform':34 'binari':981 'bio':1251,1264 'block':600 'blue':1164 'bodi':1221 'boilerpl':1429 'bool':177,888,1159 'bool.self':930 'call':493 'camelcas':726 'cannot':304,695 'case':249,251,255,259,323,443,450,530,533,540,564,576,725,893,898,1423,1437,1441,1484 'category-swift-ios-skills' 'cent':263 'chain':490 'checklist':142,145,1454 'citi':1113 'class':1119 'clean':1530 'closur':664 'coalesc':872 'codabl':2,10,17,115,119,122,126,129,133,156,165,207,232,309,820,995,1082,1085,1108,1127,1143,1147,1156,1373,1392,1549,1558,1561,1578,1585,1610 'codable-with-swiftdata':125 'codable-with-urlsess':118 'codable-with-userdefault':132 'code':1622 'codingkey':38,41,215,227,246,248,276,320,322,440,442,449,537,539,736,890,892,1419,1434,1436,1480,1590 'codingkeys.self':337,388,463,554,912 'combin':1566 'common':136,139,1229 'common-mistak':138 'compil':158 'composit':1089,1131,1555 'comput':286 'configur':109,114,611,937,1446 'conform':33,36,149,160,303,948,1456,1551,1611 'consist':1537 'constrain':1383 'contact':1120 'contain':54,59,90,94,333,385,407,459,550,594,673,693,777,809,836,850,908,1030 'container.decode':340,355,466,558,569,581,679,789,795,841,1248,1287,1302 'container.decodeifpresent':373,915,922,929,1261 'container.encode':390,395,400,853 'container.isatend':784 'container.nestedcontainer':473 'content':31,521,542,567,572,575 'contentblock':528,604 'convert':349 'convertfromsnakecas':723,1039,1452,1475 'convertfromstr':965 'converttosnakecas':744 'converttostr':957 'crash':1240 'custom':37,40,42,47,214,222,289,640,663,669,1503,1601,1609,1615 'custom-codingkey':39 'custom-decoding-and-encod':46 'data':72,77,707,720,983,994,1015,1047,1058,1080,1081,1173,1184,1195,1203,1204,1356,1368,1495,1509,1576,1589 'data-and-key-strategi':76 'date':65,69,315,351,360,608,683,685,689,697,1309,1490 'date-decoding-strategi':68 'datedecodingstrategi':1327,1486 'dateformatt':641,644 'dd':649 'debugdescript':595,694 'declar':225 'decod':13,19,43,48,66,70,83,87,108,113,182,193,223,290,329,330,344,429,455,456,508,529,546,547,603,609,619,670,696,713,747,767,773,774,806,832,833,858,879,904,905,936,988,991,1036,1056,1065,1178,1181,1189,1283,1296,1325,1345,1376,1401,1410,1450,1458,1498,1514,1546,1569,1574,1600 'decodeifpres':868,1465 'decoder.container':335,461,552,910 'decoder.datadecodingstrategy':715 'decoder.datedecodingstrategy':630,638,660,668,1040,1339 'decoder.decode':1044,1075,1353,1365 'decoder.keydecodingstrategy':722,1038,1451 'decoder.nonconformingfloatdecodingstrategy':964 'decoder.singlevaluecontainer':675,838 'decoder.unkeyedcontainer':779 'decodingerror.datacorruptederror':590,691 'deepli':496 'default':95,101,283,363,588,749,862,875,1315,1328,1468 'default-values-for-missing-key':100 'deferredtod':1330 'determinist':1520 'direct':211,859 'discrimin':515 'display':253 'displaynam':237,252 'doubl':348,435,438,1318 'double.self':356,481,487 'dpearson2699':8 'e.g':623,636 'element':752,763,769,770,781,782,787,792,800,802,1271,1279,1297,1307,1502 'element.self':790 'elements.append':791 'els':793,1032,1185,1207,1369 'email':173 'empti':365 'en':653 'enabl':901 'encod':11,18,45,50,106,111,187,190,201,292,297,379,381,382,719,739,844,846,847,934,940,1198,1205,1389,1461,1567,1584,1598 'encoder-and-decoder-configur':110 'encoder.container':386 'encoder.dataencodingstrategy':741 'encoder.dateencodingstrategy':705 'encoder.keyencodingstrategy':743 'encoder.nonconformingfloatencodingstrategy':956 'encoder.outputformatting':942 'encoder.singlevaluecontainer':851 'encoding/decoding':280,1596 'entir':755,1267 'enum':228,245,271,319,439,446,527,536,889,1433 'envelop':1050,1539 'epoch':353,362 'etc':1526 'event':308 'everi':264,1431 'exclud':277 'expect':1317 'explicit':1102 'extens':1165 'fail':753,1266 'fetchus':1000 'field':516,721 'fixup':1515 'flatten':53,58,406,415,495 'float':949 'font':896 'fontsiz':884,895,920,925 'forc':1343,1543 'force-unwrap':1342,1542 'forkey':342,357,376,392,397,402,411,468,476,482,488,502,560,571,583,591,917,924,931,1250,1263,1290,1305 'format':661,667,1338,1491 'formatt':643,662 'formatter.dateformat':645 'formatter.locale':650 'formatter.timezone':656 'func':378,843,999 'generic':1048,1532 'guard':1022,1171,1193,1361 'guid':1607 'handl':305,1233,1540 'hashabl':821 'hello':522 'heterogen':60,63,506 'heterogeneous-array':62 'http':1024 'http.statuscode':1031 'httpurlrespons':1027 'id':167,234,250,420,431,444,464,469,1001,1013,1394,1412 'identifi':652 'imag':257,524,534,577,586 'imageurl':240,256 'includ':1517 'individu':1298 'infin':951,959,961,967,969 'init':294,327,453,544,771,825,830,902,1133,1168,1504 'instead':1477,1510 'int':168,235,244,432,885,1002,1068,1071,1395,1413 'int.self':467,923 'invalid':751,762,1273,1501 'io':4,29,1095 'iso':621,1322 'iso8601':631,706,1041,1340 'iso8601dateformatter':684 'ison':1227 'isverifi':176 'item':1285,1288,1291,1300,1306 'json':217,417,419,518,855,955,1531,1575,1588,1613,1624 'jsondata':185,607 'jsondecod':22,181,602,620,714,1037,1180,1326,1570 'jsondecoder.datedecodingstrategy':612 'jsonencod':21,189,704,740,941,1197,1580 'jsonencoder.outputformatting':1516 'key':74,79,99,105,218,368,709,866,1236,1242,1257,1473,1597 'keydecodingstrategi':1474 'keyedbi':336,387,410,462,474,553,911 'kill':1280 'lat':423,451,483 'latitud':434,478 'let':166,169,172,175,178,186,233,236,239,242,310,313,316,332,352,430,433,436,458,470,549,555,566,578,599,618,642,672,676,682,712,738,768,786,822,835,880,883,886,907,939,975,982,987,1006,1014,1023,1035,1057,1060,1066,1069,1072,1172,1177,1194,1200,1245,1258,1284,1299,1324,1350,1362,1393,1396,1411,1414 'lng':425,452,489 'local':651 'locat':422,445,471,477 'location.decode':480,486 'locationkey':447 'locationkeys.self':475 'longitud':437,484 'lossi':81,85,745,1497 'lossy-array-decod':84 'lossyarray':766,1294,1303 'manual':1418,1479 'map':730 'match':614,701,1335,1487 'messag':1397,1415 'meta':1061,1062,1064 'mismatch':1311 'miss':98,104,370,865,1234,1256,1472 'mistak':137,140,1230 'mix':511 'mm':648 'model':1093,1118,1432 'multipl':491,666 'must':267 'name':170,254,311,324,338,343,391,393,728,1122,1134,1140,1359,1440 'nan':950,962,963,970,971 'nativ':1098 'navig':413 'need':737,1378,1464 'negativeinfin':960,968 'nest':51,56,404,416,497,504 'nested-and-flattened-contain':55 'nestedcontain':409,492 'nestedunkeyedcontain':501 'nil':871,1138,1187,1254 'nil-coalesc':870 'non':947 'non-conform':946 'notif':900 'notificationsen':887,899,927,932 'omit':272 'onboard':1226 'one':750,1270,1277 'option':1235,1346,1470 'output':1522 'overrid':293 'page':1067 'past':798 'pattern':1625 'pic.jpg':526 'place':428 'plistencod':976 'plistencoder.encode':985 'plistencoder.outputformat':978 'positiveinfin':958,966 'posix':655 'post':1513 'post-decod':1512 'pref':1218 'prefer':192 'prefs.showonboarding':1228 'prettyprint':943 'price':261 'priceinc':243,260 'primit':811 'print':1357 'privat':803,1216 'product':231 'properti':153,266,274 'propertylistdecod':973,990 'propertylistencod':972,977 'protocol':1565,1594 'provid':281,874 'rawrepresent':1150,1167,1553 'rawvalu':823,826,829,839,854,1169,1191 'rawvalue.data':1174 'read':196,1404 'read-on':195,1403 'refer':146,147,1560 'relat':24 'renam':216 'requir':213 'respons':199,1016,1025,1053,1407 'return':688,1042,1186,1208,1209,1253,1370 'review':141,144,1453 'review-checklist':143 'safeti':814 'sampl':1621 'second':635 'secondsfromgmt':658 'secondssince1970':639 'self':375,573,585,605,1078,1188,1199,1289,1304 'self.address':1141 'self.elements':801 'self.name':1139 'self.rawvalue':828 'self.self':1182 'send':1321 'separ':288 'set':699,878,986,1332 'settings.self':992 'settingsview':1212 'show':1225 'showonboard':1158 'simpl':1421,1482 'singl':88,92,807 'single-value-contain':91 'singlevaluecontain':816,1528 'size':897 'skill':5,6 'skip':761,1500 'snake':724,1422,1483 'sortedkey':944,1518 'sosumi.ai':1563,1572,1582,1592,1604,1618 'sosumi.ai/documentation/foundation/archives_and_serialization/using_json_with_custom_types/)':1617 'sosumi.ai/documentation/foundation/encoding-and-decoding-custom-types/)':1603 'sosumi.ai/documentation/foundation/jsondecoder/)':1571 'sosumi.ai/documentation/foundation/jsonencoder/)':1581 'sosumi.ai/documentation/swift/codable/)':1562 'sosumi.ai/documentation/swift/codingkey/)':1591 'source-dpearson2699' 'store':152,265,1129,1146 'strategi':67,71,75,80,610,702,710,1310,1316,1333 'street':1110 'string':171,174,238,247,312,318,321,374,441,448,532,538,677,687,698,734,824,827,882,891,1009,1111,1114,1117,1123,1135,1163,1170,1192,1201,1202,1210,1323,1398,1416,1435 'string.self':341,559,570,680,842,916,1249,1262 'struct':163,230,307,427,765,804,818,877,1054,1063,1086,1106,1128,1154,1211,1390,1408,1559 'structur':498 'support':1099 'swift':1,3,9,14,27,162,229,306,418,517,617,711,764,817,876,938,974,998,1105,1153,1237,1274,1312,1347,1379,1425 'swiftdata':124,128,1084,1092,1097,1554 'switch':562 'synthes':159,302 'system':919 't10':627 'tag':317,326,371,377,401,403 'target':26 'test':1521 'text':520,531,565,574 'theme':881,894,913,918 'throw':331,383,457,548,589,690,775,834,848,906,1004,1033 'timeintervalsince1970':361 'timestamp':314,325,346,358,359,398,633 'timestamp.timeintervalsince1970':396 'timezon':657 'toggl':1224 'totalpag':1070 'transform':300,1104,1508 'tri':180,188,334,339,354,372,389,394,399,460,465,472,479,485,551,557,568,580,601,674,678,778,788,794,837,840,852,909,914,921,928,984,989,1017,1043,1074,1179,1196,1247,1260,1286,1301,1352,1364 'true':933,1160 'type':15,512,519,523,541,556,561,563,592,597,598,813,1385,1455,1524,1550,1579,1586,1602,1616 'unix':345,632 'unknown':596 'unnecessarili':1382 'unreli':1494 'unwrap':1344,1544 'url':241,258,525,535,543,579,584,587,1007,1008,1021,1444 'url.self':582 'urlsess':117,121,997 'urlsession.shared.data':1019 'us':654 'use':16,206,408,500,513,757,815,867,1175,1293,1372,1400,1466,1476,1496,1527,1535,1557,1612 'user':164,179,191,727,1005,1073,1077,1351,1358,1363,1439 'user.self':183,1045,1354,1366 'userdefault':131,135,1145 'userid':819,861,1525 'usernam':733,1438 'userpref':1215 'userprefer':1155,1166,1219 'usr':856 'utf8':1176,1206 'valid':954,1506 'valu':89,93,96,102,284,808,863,1148,1246,1259,1547 'var':384,732,776,780,849,1109,1112,1115,1121,1124,1157,1161,1190,1217,1220 'verbos':1428 'via':1149 'view':1213,1223 'whole':1282 'without':219,1101 'withoutescapingslash':945 'work':1087 'wrap':810,1052 'wrapper':759,1523,1534 'write':204,220 'write-on':203 'xml':979 'yyyi':647 'yyyy-mm-dd':646 'zipcod':1116","prices":[{"id":"da050b7c-b665-4669-8b0c-5909f101e97c","listingId":"447e3fa7-e97b-4389-a876-439ef5cdc718","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"dpearson2699","category":"swift-ios-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T20:37:20.925Z"}],"sources":[{"listingId":"447e3fa7-e97b-4389-a876-439ef5cdc718","source":"github","sourceId":"dpearson2699/swift-ios-skills/swift-codable","sourceUrl":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/swift-codable","isPrimary":false,"firstSeenAt":"2026-04-18T22:01:19.851Z","lastSeenAt":"2026-04-22T00:53:44.867Z"},{"listingId":"447e3fa7-e97b-4389-a876-439ef5cdc718","source":"skills_sh","sourceId":"dpearson2699/swift-ios-skills/swift-codable","sourceUrl":"https://skills.sh/dpearson2699/swift-ios-skills/swift-codable","isPrimary":true,"firstSeenAt":"2026-04-18T20:37:20.925Z","lastSeenAt":"2026-04-22T03:40:39.261Z"}],"details":{"listingId":"447e3fa7-e97b-4389-a876-439ef5cdc718","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"dpearson2699","slug":"swift-codable","source":"skills_sh","category":"swift-ios-skills","skills_sh_url":"https://skills.sh/dpearson2699/swift-ios-skills/swift-codable"},"updatedAt":"2026-04-22T03:40:39.261Z"}}