{"id":1036,"url":"https://github.com/artemstepanenko/Dekoter","last_synced_at":"2025-07-30T20:31:08.887Z","repository":{"id":56908375,"uuid":"77477982","full_name":"artemstepanenko/Dekoter","owner":"artemstepanenko","description":"NSCoding's counterpart for Swift structs.","archived":false,"fork":false,"pushed_at":"2019-09-27T15:49:28.000Z","size":375,"stargazers_count":25,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-07-15T01:19:49.393Z","etag":null,"topics":["decoding","swift","swift-extensions","swift-library","swift-structs","userdefaults"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/artemstepanenko.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-27T19:27:51.000Z","updated_at":"2022-05-15T08:56:23.000Z","dependencies_parsed_at":"2022-08-21T03:50:20.553Z","dependency_job_id":null,"html_url":"https://github.com/artemstepanenko/Dekoter","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/artemstepanenko/Dekoter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artemstepanenko%2FDekoter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artemstepanenko%2FDekoter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artemstepanenko%2FDekoter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artemstepanenko%2FDekoter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/artemstepanenko","download_url":"https://codeload.github.com/artemstepanenko/Dekoter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/artemstepanenko%2FDekoter/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267935234,"owners_count":24168286,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decoding","swift","swift-extensions","swift-library","swift-structs","userdefaults"],"created_at":"2024-01-05T20:15:37.568Z","updated_at":"2025-07-30T20:31:08.586Z","avatar_url":"https://github.com/artemstepanenko.png","language":"Swift","funding_links":[],"categories":["Data Structures / Algorithms"],"sub_categories":["Getting Started","Other free courses","Linter"],"readme":"# Dekoter\n\n[![Build Status](https://travis-ci.org/artemstepanenko/Dekoter.svg?branch=master)](https://travis-ci.org/artemstepanenko/Dekoter)\n[![Version](https://img.shields.io/cocoapods/v/Dekoter.svg?style=flat)](http://cocoapods.org/pods/Dekoter)\n[![License](https://img.shields.io/cocoapods/l/Dekoter.svg?style=flat)](http://cocoapods.org/pods/Dekoter)\n[![Platform](https://img.shields.io/cocoapods/p/Dekoter.svg?style=flat)](http://cocoapods.org/pods/Dekoter)\n\n- [Why You Might Be Interested](#why-you-might-be-interested)\n- [How Much Familiar It Feels](#how-much-familiar-it-feels)\n- [One More Example](#one-more-example)\n - [What We've Learned from It](#what-weve-learned-from-it)\n- [Features](#features)\n - [Save an Object to UserDefaults](#save-an-object-to-userdefaults)\n - [Archive and Unarchive an Object](#archive-and-unarchive-an-object)\n - [JSON](#json)\n- [Micromission](#micromission)\n- [Why Dekoter](#why-dekoter)\n- [Installation](#installation)\n - [CocoaPods](#cocoapods)\n- [Collaboration](#collaboration)\n- [License](#license)\n\n## Why You Might Be Interested\n\nFills a gap left by the missing `NSCoding`'s support for Swift structs.\nIf you've ever implemented `NSCoding`, `Koting` will be familiar to you as well.\n\n## How Much Familiar It Feels\n\nA quick reminder how to implement `NSCoding`:\n\n```swift\nclass Cat: NSObject, NSCoding {\n\n    let name: String\n\n    init(name: String) {\n        self.name = name\n    }\n\n    // MARK: - NSCoding\n\n    private struct Key {\n        static let name = \"name\"\n    }\n\n    func encode(with aCoder: NSCoder) {\n        aCoder.encode(name, forKey: Key.name)\n    }\n\n    required convenience init?(coder aDecoder: NSCoder) {\n        guard let name = aDecoder.decodeObject(forKey: Key.name) as? String else {\n            return nil\n        }\n        self.init(name: name)\n    }\n}\n```\n\nLet's compare it to `Koting`:\n\n```swift\nstruct Cat: Koting {\n\n    let name: String\n\n    // MARK: - Koting\n\n    private struct Key {\n        static let name = \"name\"\n    }\n\n    init?(koter: Koter) {\n        guard let name: String = koter.dekotObject(forKey: Key.name) else {\n            return nil\n        }\n        self.init(name: name)\n    }\n\n    func enkot(with koter: Koter) {\n        koter.enkotObject(name, forKey: Key.name)\n    }\n}\n```\n\nThus, not much different besides naming.\n\nTo summarize:\n\n- Add the `Koting` protocol to the class declaration.\n- Implement `init?(koter:)` and func `enkot(with:)`.\n- Done!\n\nOnce it's done, the compiler is happy, and you can convert objects to `Data` and back.\n\n```swift\nlet puss = Cat(name: \"Puss\")\nlet data = NSKeyedArchiver.de_archivedData(withRootObject: puss)\nguard let againPuss: Cat = NSKeyedUnarchiver.de_unarchiveObject(with: data) else { return }\n```\n\n## One More Example\n\nThis one is going to depict most of the Dekoter's features.\n\n```swift\nstruct Cat {\n\n    enum Sex: Int {\n        case male\n        case female\n    }\n\n    let name: String\n    let surname: String?\n    let sex: Sex\n    let nationality: String\n    let birthPlace: Place?\n\n    // MARK: - Koting\n\n    private struct Key {\n        static let name = \"name\"\n        static let surname = \"surname\"\n        static let sex = \"sex\"\n        static let nationality = \"nationality\"\n        static let birthPlace = \"birthPlace\"\n    }\n\n    init?(koter: Koter) {\n        guard let name: String = koter.dekotObject(forKey: Key.name),\n            let nationality: String = koter.dekotObject(forKey: Key.nationality),\n            let sexValue: Int = koter.dekotObject(forKey: Key.sex),\n            let sex = Sex(rawValue: sexValue) else {\n\n            return nil\n        }\n        let surname: String? = koter.dekotObject(forKey: Key.surname)\n        let birthPlace: Place? = koter.dekotObject(forKey: Key.birthPlace)\n        self.init(name: name, surname: surname, sex: sex, nationality: nationality, birthPlace: birthPlace)\n    }\n\n    func enkot(with koter: Koter) {\n        koter.enkotObject(name, forKey: Key.name)\n        koter.enkotObject(surname, forKey: Key.surname)\n        koter.enkotObject(sex.rawValue, forKey: Key.sex)\n        koter.enkotObject(nationality, forKey: Key.nationality)\n        koter.enkotObject(birthPlace, forKey: Key.birthPlace)\n    }\n}\n```\n\n### What We've Learned from It\n\n- *It's okay to have optional properties.*\n\nAs you can see, there're two optional properties. To encode them you don't do anything special, `enkotObject(_, forKey:)` takes optional as the first argument. For decoding you use `dekotObject(forKey:)` which also returns optional and it's up to you how whether you unwrap it or not.\n\n- *`Koter` supports the same parameter types as `NSCoding` and additionally types which implement `Koting`.*\n\nIn the example above `Cat` has an optional `birthPlace` property of a type `Place`.\n\n- *There's only one method for encoding and one – for decoding.*\n\nRegardless the type, you use the same methods: `enkotObject(_, forKey:)` for encoding and `dekotObject(forKey:)` for decoding. These methods are generic, they derive a type based on the expected return value, that's why you should always explicitly specify it.\n\n## Features\n\n### Save an Object to UserDefaults\n\nThere are two methods implemented in a `UserDefaults` extension: `de_set(_, forKey:)` and `de_object(forKey:)`\n\n```swift\nlet murzik = Cat(name: \"Murzik\", surname: nil, sex: .male, nationality: \"GER\", birthPlace: nil)\nuserDefaults.de_set(murzik, forKey: \"cat\")\nlet againMurzik: Cat? = userDefaults.de_object(forKey: \"cat\")\n```\n\nand\n\n```swift\nlet sonya = Cat(name: \"Sonya\", surname: \"Kryvonis\", sex: .female, nationality: \"UA\", birthPlace: Place(country: \"Ukraine\", city: \"Lviv\"))\nlet puff: Cat = Cat(name: \"Puff\", surname: nil, sex: .female, nationality: \"US\", birthPlace: nil)\nlet cats = [ sonya, puff ]\nuserDefaults.de_set(cats, forKey: Key.cat)\nguard let againCats: [Cat] = userDefaults.de_object(forKey: Key.cat) else { return }\n```\n\n### Archive and Unarchive an Object\n\nThe library contains two extensions for `NSKeyedArchiver` and `NSKeyedUnarchiver` with methods for objects which implement the `Koting` protocol.\n\n```swift\nlet emma = Cat(name: \"Emma\", surname: \"Lambert\", sex: .female, nationality: \"FR\", birthPlace: Place(country: \"France\", city: \"Marseille\"))\nlet data = NSKeyedArchiver.de_archivedData(withRootObject: emma)        \nguard let againEmma: Cat = NSKeyedUnarchiver.de_unarchiveObject(with: data) else { return }\n```\n\nand\n\n```swift\nlet sonya = Cat(name: \"Sonya\", surname: \"Kryvonis\", sex: .female, nationality: \"UA\", birthPlace: Place(country: \"Ukraine\", city: \"Lviv\"))\nlet puff: Cat = Cat(name: \"Puff\", surname: nil, sex: .female, nationality: \"US\", birthPlace: nil)\nlet cats = [ sonya, puff ]\nlet data = NSKeyedArchiver.de_archivedData(withRootObject: cats)\nguard let againCats: [Cat] = NSKeyedUnarchiver.de_unarchiveObject(with: data) else { return }\n```\n\n### JSON\n\nA `JSONSerialization` extension makes deserialization from JSON very easy.\n\n```swift\nlet oneCat: Cat? = JSONSerialization.de_jsonObject(with: oneCatData)\nlet cats: [Cat]? = JSONSerialization.de_jsonObject(with: catsData)\n```\n\nFor structs which make use only of this feature there's no need to implement the `Koting` protocol (contains 2 methods), instead implement a `Dekoting` protocol (only 1 method).\n\n## Micromission\n\nThe library is small but proud of its mission, though the latter is also not that big. It's willing to serve developers as good as `NSCoding` does. Developers shouldn't feel lost and disappointed without a convenient tool to convert their Swift structs to `Data` and back.\n\n## Why Dekoter\n\nYou might have noticed a few cats here and there. There's a reason.\n\"Kot\" in some slavic languages means \"cat\", and it sounds similar to \"code\".\n\n\"enkot\" -\u003e \"encode\"\n\n\"dekot\" -\u003e \"decode\"\n\n\"koter\" -\u003e \"coder\"\n\n\"koting\" -\u003e \"coding\"\n\n\"dekoter\" -\u003e \"decoder\"\n\n## Installation\n\n### CocoaPods\n\nAdd `pod 'Dekoter'` similar to the following to your Podfile:\n\n```ruby\ntarget 'MyApp' do\n  pod 'Dekoter'\nend\n```\n\nThen run a `pod install` inside your terminal, or from CocoaPods.app.\n\n## Collaboration\n\nDear friends, your help is more than welcome!\nThere're multiple ways to support the project.\n\n- [Create an issue.](https://github.com/artemstepanenko/Dekoter/issues/new)\n\nif you find a problem, or you know how to improve, or you have a question.\n\n- [Create a pull request.](https://github.com/artemstepanenko/Dekoter/compare)\n\nif you develop something important (previously filed as an issue).\n\n- [Send me an email.](mailto:artem.stepanenko.1@gmail.com)\n\nif you want to share your either positive or negative experience using the library and have a hard time expressing it in a form of issue. Or, maybe, you don't want to make it publicly available.\n\nI'm always happy to read an email from you.\n\n## License\n\nIt's available under the MIT license. See the [LICENSE](LICENSE) file for more info.\n\n![](https://github.com/artemstepanenko/Dekoter/blob/master/cat.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartemstepanenko%2FDekoter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fartemstepanenko%2FDekoter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fartemstepanenko%2FDekoter/lists"}