{"id":21437618,"url":"https://github.com/gabrieltheodoropoulos/gtcodable","last_synced_at":"2025-03-16T23:41:48.163Z","repository":{"id":79559034,"uuid":"124279782","full_name":"gabrieltheodoropoulos/GTCodable","owner":"gabrieltheodoropoulos","description":"A custom protocol in Swift that lets you convert any struct or class object to dictionary, JSON, Plist or archived data and vice versa, save to files, load from files, initialise objects, encode, decode and more, in an amazingly simple, fast and natural way!","archived":false,"fork":false,"pushed_at":"2018-10-08T11:57:46.000Z","size":46,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-23T09:43:37.944Z","etag":null,"topics":["archive","decodable","dictionary","encodable","json","plist","protocol","protocol-oriented-programming","reflection","savefiles","swift"],"latest_commit_sha":null,"homepage":"https://gtiapps.com/?p=4411","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/gabrieltheodoropoulos.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-07T18:49:22.000Z","updated_at":"2019-11-29T03:49:46.000Z","dependencies_parsed_at":"2023-03-13T20:09:49.397Z","dependency_job_id":null,"html_url":"https://github.com/gabrieltheodoropoulos/GTCodable","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieltheodoropoulos%2FGTCodable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieltheodoropoulos%2FGTCodable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieltheodoropoulos%2FGTCodable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieltheodoropoulos%2FGTCodable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gabrieltheodoropoulos","download_url":"https://codeload.github.com/gabrieltheodoropoulos/GTCodable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243950792,"owners_count":20373664,"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","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":["archive","decodable","dictionary","encodable","json","plist","protocol","protocol-oriented-programming","reflection","savefiles","swift"],"created_at":"2024-11-23T00:27:58.830Z","updated_at":"2025-03-16T23:41:48.141Z","avatar_url":"https://github.com/gabrieltheodoropoulos.png","language":"Swift","readme":"About GTCodable\r\n---------------\r\n\r\nAs an iOS developer, I always wanted to have a really fast and natural way to convert data kept in a class or struct properties to dictionaries (key-value pairs), to JSON, or Plist files and vice versa. I wanted that mechanism to be totally generic and datatype independent, regardless of the number of properties and their kind existing in a class or a struct. I would always like to have a tool that would let me convert an object's data so it's easy to use them in RESTful APIs, or to assign fetched values to object properties without much effort. I also wanted to make it easy to save objects' data to files into the documents directory if possible in one move only, and to initialise objects by loading the stored data. And on top of all, I wanted something that would be easy to remember and use.\r\n\r\nSo, the **GTCodable** protocol came to life! It’s a combination of three different *forces* in Swift:\r\n\r\n*   _POP_ (Protocol Oriented Programming): It’s a _protocol_, it’s not a class, it’s not a struct. It’s a protocol with its extension and default function implementation, that allows any other custom class, struct or enum to conform to it and use its features right away.\r\n*   _Reflection_: The need to come up with a solution that would feel really natural without any weird workarounds led me towards Reflection, which even though is not that powerful in Swift and caused me a few troubles along the way, it made the difference by enabling me to access properties and values of objects in runtime and perform certain actions on them in a fully automatic fashion. For example, without reflection it wouldn’t be possible _to convert an object in to a dictionary_ (see more next) with GTCodable.\r\n*   _Encodable \u0026 Decodable Protocols_: Or in one word, the new _Codable_ protocol in Swift 4, which lets us JSON encode and decode at a blink of the eye. It’s not like the old _NSCoding_ protocol where we had to manually specify the properties to encode and decode. Encodable \u0026 Decodable protocols have vital effect on GTCodable.\r\n\r\nWith GTCodable protocol I’m not reinventing the wheel, I’m just putting together different tools that Swift provides us with and I’m automating certain tasks. In a fast forward mode, here’s what GTCodable has to offer:\r\n\r\n*   Convert an object into a dictionary, JSON, Plist, or archived data (archive made by NSKeyedArchiver) by just calling a simple method for each case (I don’t think it could be faster and more natural than that).\r\n*   Save a converted object as described above to the respective file format.\r\n*   Save manually JSON data, dictionary, or archive data to custom URLs with custom names.\r\n*   Exclude properties from being encoded or converted.\r\n*   Convert objects to dictionaries (have I said that?).\r\n*   Load data from JSON, Plist, or data file by calling one method only.\r\n*   Initialize objects and populate values to their properties with one function call only.\r\n*   Combine and nest custom types that conform to GTCodable protocol.\r\n*   Use collections and dictionaries and combination of them (dictionaries inside collections, collections inside dictionaries, etc) of objects conforming to GTCodable protocol.\r\n*   Use assistive functions to get String representations of JSON data, values of properties of an object, even the path to the documents directory so you don’t have to remember and type it again any longer.\r\n\r\nOf course, like every new game that respects itself, there are some rules to follow, so please keep reading about how to use GTCodable, or at least read the Rules section later in this document.\r\n\r\n\r\nHow to Use GTCodable\r\n--------------------\r\n\r\nClone or download the repository and drag the _GTCodable.swift_ file into your iOS Swift project.\r\n\r\n\r\nGTCodable Provided Functions At A Glance\r\n----------------------------------------\r\n\r\nHere’s a list of functions provided by the GTCodable protocol. Names are self explanatory, and more details about each function exist in the next parts.\r\n\r\n```swift\r\nfunc toJson() -\u003e Data?\r\nfunc toJSON(fromDictionary:) -\u003e Data?\r\nfunc toDictionary() -\u003e [String: Any]\r\nfunc toDictionary(fromJson:) -\u003e [String: Any]?\r\nfunc archive() -\u003e Data\r\nfunc save(json:toURL:) -\u003e Bool\r\nfunc saveJSON() -\u003e Bool\r\nfunc savePlist(fromDictionary:toURL:) -\u003e Bool\r\nfunc savePlist() -\u003e Bool\r\nfunc save(archive:toURL:) -\u003e Bool\r\nfunc saveArchive() -\u003e Bool\r\nfunc loadJSON(fromURL:) -\u003e Data?\r\nfunc loadPlist(fromURL:) -\u003e [String: Any]?\r\nfunc loadArchive(fromURL:) -\u003e Data?\r\nmutating func initialize(usingJSON:) -\u003e Bool\r\nmutating func initialize(usingPlist:) -\u003e Bool\r\nmutating func initialize(usingArchive:) -\u003e Bool\r\nmutating func initFromJSON() -\u003e Bool\r\nmutating func initFromPlist() -\u003e Bool\r\nmutating func initFromArchive() -\u003e Bool\r\nfunc getDocDirPath() -\u003e String\r\nfunc getRaw() -\u003e Any?\r\nfunc getTextualRepresentation(fromJson:) -\u003e String?\r\nfunc describeSelf() -\u003e String\r\n```\r\n\r\nGTCodable protocol contains some additional private functions that perform important work behind the scenes, but there’s no need to be listed here as they are used internally by the protocol only.\r\n\r\n\r\nUsing GTCodable\r\n---------------\r\n\r\nConsider the following `struct` that conforms to GTCodable protocol:\r\n\r\n```swift\r\nstruct User: GTCodable {\r\n    var id: Int?\r\n    var username: String?\r\n    var email: String?\r\n    var avatarFile: String?\r\n}\r\n```\r\n\r\nLet’s initialise an object of type `User`:\r\n\r\n```swift\r\nvar user = User()\r\nuser.id = 11\r\nuser.username = \"superman\"\r\nuser.email = \"superman@superheroes.org\"\r\nuser.avatarFile = \"superman.png\"\r\n```\r\n\r\nThen, encoding into JSON and saving to file:\r\n\r\n```swift\r\n_ = user.saveJSON()\r\n```\r\n\r\nSaving a _Plist_ file containing the properties and their values:\r\n\r\n```swift\r\n_ = user.savePlist()\r\n```\r\n\r\nArchiving and saving to file:\r\n\r\n```swift\r\n_ = user.saveArchive()\r\n```\r\n\r\nThe outcome:\r\n\r\n![Generated files](http://gtiapps.com/wp-content/uploads/2018/03/gtcodable_output.png)\r\n\r\nGenerated files\r\n\r\nAll the above three functions return a Bool value that indicates whether each process was successful or not.\r\n\r\nWhen using any of the functions that were just presented, the struct’s name is used automatically as the file name with the following cases applying:\r\n\r\n*   For JSON files, the _json_ extension is appended.\r\n*   For Plist files, the _plist_ extension is appended.\r\n*   For archives, no extension is appended.\r\n\r\nNote that a directory called \"appdata\" is created automatically in the documents directory. It’s the place where GTCodable stores files and loads from.\r\n\r\nBesides the above convenient functions to save an object using different formats by calling a single method only, you can also use the following methods to encode or convert and get the results as objects:\r\n\r\n```swift\r\nif let json = user.toJson() {\r\n    if let jsonToString = user.getTextualRepresentation(fromJson: json) {\r\n        print(jsonToString)\r\n    }\r\n}\r\n```\r\n\r\nThe `toJson()` function returns a JSON encoded object, if encoding is successful. The `getTextualRepresentation(fromJson:)` is another function provided by the GTCodable protocol, and returns a textual representation of a JSON object as its name suggests. Here’s what it’s printed:\r\n\r\n    {\r\n      \"avatarFile\" : \"superman.png\",\r\n      \"email\" : \"superman@superheroes.org\",\r\n      \"id\" : 11,\r\n      \"username\" : \"superman\"\r\n    }\r\n\r\nTo get an archived object:\r\n\r\n```swift\r\nlet archive = user.archive()\r\n// archive is a Data object. Do something with it.\r\n```\r\n\r\nHowever, one of the most interesting cases is that you can get a _dictionary_ containing all properties and their values, which practically means that _you can convert an object into a `[String: Any]` dictionary_:\r\n\r\n```swift\r\nlet dictionary = user.toDictionary()\r\nprint(dictionary)\r\n```\r\n\r\nOutput:\r\n\r\n```swift\r\n[\"avatarFile\": Optional(\"superman.png\"), \"email\": Optional(\"superman@superman.com\"), \"id\": Optional(11), \"username\": Optional(\"superman\")]\r\n```\r\n\r\nIn addition to the `toDictionary()` function, you can use another one named `toDictionary(fromJson:)` if you want to get a dictionary from a JSON object:\r\n\r\n```swift\r\nif let json = user.toJson() {\r\n    let dict = user.toDictionary(fromJson: json)\r\n}\r\n```\r\n\r\nGTCodable allows you to do the exact opposite fast as well, meaning to create a JSON object based on a given dictionary. For example:\r\n\r\n```swift\r\nlet dictionary = user.toDictionary()\r\nif let json = user.toJSON(fromDictionary: dictionary) {\r\n    // Do something with the json object.\r\n}\r\n```\r\n\r\nTo manually save a JSON object to a custom URL use the `save(json:toURL:)` function:\r\n\r\n```swift\r\nif let json = user.toJson() {    \r\n    let url = [A custom URL]\r\n    user.save(json: json, toURL: url)\r\n}\r\n```\r\n\r\nIn a similar fashion, you can manually save a dictionary to a custom URL:\r\n\r\n```swift\r\nlet dictionary = user.toDictionary()\r\nlet url = [A custom URL]\r\nuser.savePlist(fromDictionary: dictionary, toURL: url)\r\n```\r\n\r\nSame as above, if you have an archived object you can manually save it in case you don’t want to use the `saveArchive()` convenient function:\r\n\r\n```swift\r\nlet archive = user.archive()\r\nlet url = [A custom URL]\r\nuser.save(archive: archive, toURL: url)\r\n```\r\n\r\n### Loading and Initializing With GTCodable Protocol\r\n\r\nGoing to the opposite direction, here’s how to load data from files that were originally created using any of the `saveJSON()`, `savePlist()` or `saveArchive()` functions.\r\n\r\nLoading from from the default JSON file:\r\n\r\n```swift\r\nvar anotherUser = User()\r\n_ = anotherUser.initFromJSON()\r\n```\r\n\r\nFrom the default Plist file:\r\n\r\n```swift\r\n_ = anotherUser.initFromPlist()\r\n```\r\n\r\nAnd from the default file with archived data:\r\n\r\n```swift\r\n_ = anotherUser.initFromArchive()\r\n```\r\n\r\nThese three functions return a `Bool` value indicating whether each action was performed successfully or not.\r\n\r\nExcept for the above convenient and fast functions, you can also load manually from custom URLs. Here’s how you can load JSON data:\r\n\r\n```swift\r\nlet url = [A custom URL]\r\nif let json = user.loadJSON(fromURL: url) {\r\n    // json is a Data object, do something with it.\r\n} \r\n```\r\n\r\nLoading from a Plist file:\r\n\r\n```swift\r\nlet url = [A custom URL]\r\nif let dict = user.loadPlist(fromURL: url) {\r\n    // dict is a [String: Any] object, do something with it.\r\n}\r\n```\r\n\r\nLoading archived data:\r\n\r\n```swift\r\nlet url = [A custom URL]\r\nif let archive = user.loadArchive(fromURL: url) {\r\n    // archive is a Data object, do something with it.\r\n}\r\n```\r\n\r\nLastly, you can populate data from a JSON object, dictionary, or an archive to a GTCodable-conforming object using any of the three \"initialize(using…)\" functions demonstrated next.\r\n\r\n```swift\r\nvar user = User()\r\nlet json = [A JSON object]\r\n_ = user.initialize(usingJSON: json)\r\n```\r\n\r\n```swift\r\nvar user = User()\r\nlet dict = [A [String: Any] dictionary]\r\n_ = user.initialize(usingPlist: dict)    \r\n```\r\n\r\n```swift\r\nvar user = User()\r\nlet arhive = [A NSKeyedArchiver object]\r\n_ = user.initialize(usingArchive: archive)    \r\n```\r\n\r\nExcluding Properties\r\n--------------------\r\n\r\nYou won’t always want to include all properties when encoding an object as JSON or converting to dictionary. Suppose, for example, that we don’t want to include the `avatarFile` property when saving our JSON encoded data to file. With GTCodable is really easy to ignore properties, as all you need is _to declare an array of String objects named mandatorily **excludedProperties**, and append the names of the properties you want to be excluded to it_.\r\n\r\nIn action, and in the `User` struct, the easiest way to do it is as shown next:\r\n\r\n```swift\r\nstruct User: GTCodable {\r\n    // Other property declarations here.\r\n\r\n    var excludedProperties = [\"avatarFile\"]\r\n}    \r\n```\r\n\r\nOf course, if more properties had to be ignored, then their names should be appended to that array. The following excludes not only the `avatarFile`, but the `id` and `username` properties as well:\r\n\r\n```swift\r\nvar excludedProperties = [\"avatarFile\", \"id\", \"username\"]    \r\n```\r\n\r\nIt’s really important to stress this: _Properties you want to be excluded from encoding or conversion must be declared as Optionals_, like for example the following property:\r\n\r\n```swift\r\nvar avatarFile: String? \r\n```\r\n\r\nin the `User` struct. This is a rule, and please respect it to avoid problems.\r\n\r\nAs an alternative, the `excludedProperties` array can be declared in the struct as Optional:\r\n\r\n```swift\r\nstruct User: GTCodable {\r\n    // Other property declarations.\r\n\r\n    var excludedProperties: [String]?\r\n} \r\n```\r\n\r\nThen, and after the initialisation of a `User` object, we can add values to it:\r\n\r\n```swift\r\nvar user = User()\r\n\r\nuser.excludedProperties = [\"avatarFile\"]\r\n```\r\n\r\nAlways make sure that the property names you add to the `excludedProperties` array match to the actual names and there are no typos.\r\n\r\nAdvanced Usage\r\n--------------\r\n\r\nThe samples demonstrated previously are quite simple, and of course GTCodable’s powerfulness doesn’t stop there. Let’s extend our example by creating the following struct:\r\n\r\n```swift\r\nstruct AdditionalInfo: GTCodable {\r\n    var firstName: String?\r\n    var lastName: String?\r\n    var gender: Gender?\r\n\r\n    enum Gender: Int, GTCodable {\r\n        case male = 1\r\n        case female\r\n    }\r\n}    \r\n```\r\n\r\nBoth the `AdditionalInfo` struct and the `Gender` enum conform to GTCodable protocol, and this is a requirement for custom types. Notice also that a specific type (Int) is defined for the `Gender` enum, which is also another requirement.\r\n\r\nUpdating the `User` struct now:\r\n\r\n```swift\r\nstruct User: GTCodable {\r\n    // Other property declarations\r\n\r\n    var additionalInfo: AdditionalInfo?\r\n} \r\n```\r\n\r\nAnd initialising such an object:\r\n\r\n```swift\r\nvar user = User()\r\n// Other property configuration here\r\n\r\nuser.additionalInfo = AdditionalInfo(firstName: \"Clark\", lastName: \"Kent\", gender: .male) \r\n```\r\n\r\nBy JSON-encoding the `user` object, the `additionalInfo` property will be included to the produced JSON data:\r\n\r\n```swift\r\n_ = user.saveJSON()\r\n\r\n\r\n{\r\n  \"additionalInfo\" : {\r\n    \"firstName\" : \"Clark\",\r\n    \"gender\" : 1,\r\n    \"lastName\" : \"Kent\"\r\n  },\r\n  \"email\" : \"superman@superheroes.org\",\r\n  \"id\" : 11,\r\n  \"username\" : \"superman\"\r\n}    \r\n```\r\n\r\nThe same, for example, will happen if we get a dictionary from the `user` object:\r\n\r\n```swift\r\n_ = user.toDictionary()    \r\n```\r\n\r\n```swift\r\n[\"additionalInfo\": [\"lastName\": Optional(\"Kent\"), \"gender\": 1, \"firstName\": Optional(\"Clark\")], \"email\": Optional(\"superman@superheroes.org\"), \"id\": Optional(11), \"username\": Optional(\"superman\")] \r\n```\r\n\r\nWhat if we would want to exclude a property from the `AdditionalInfo` struct though? How would we exclude the `lastName`?\r\n\r\nTo do that, declare the `excludedProperties` String array in the `AdditionalInfo` struct, and add the name of the property or properties you want to be ignored:\r\n\r\n```swift\r\nstruct AdditionalInfo: GTCodable {\r\n    // Other property declarations\r\n\r\n    var excludedProperties = [\"lastName\"]\r\n} \r\n```\r\n\r\nIn the output JSON the last name is missing now:\r\n\r\n    {\r\n      \"additionalInfo\" : {\r\n        \"firstName\" : \"Clark\",\r\n        \"gender\" : 1\r\n      },\r\n      \"email\" : \"superman@superheroes.org\",\r\n      \"id\" : 11,\r\n      \"username\" : \"superman\"\r\n    }\r\n    \r\n\r\nAlternatively, you can add values to the `excludedProperties` array while configuring the `user` object. At first, you need to declare the `excludedProperties` as an optional in the `AdditionalInfo` struct:\r\n\r\n```swift\r\nstruct AdditionalInfo: GTCodable {\r\n    // Other property declarations\r\n\r\n    var excludedProperties: [String]?\r\n}\r\n```\r\n\r\nThen:\r\n\r\n```swift\r\nvar user = User()\r\n// Other User property configuration here\r\n\r\nuser.additionalInfo = AdditionalInfo(firstName: \"Clark\", lastName: \"Kent\", gender: .male)\r\nuser.additionalInfo?.excludedProperties = [\"lastName\"]\r\n```\r\n\r\n**Important Tip**: Suppose that you have properties to ignore in the `AdditionalInfo` struct, but not in the `User`, which contains an object of the `AdditionalInfo`. Normally, you would expect to declare the `excludedProperties` array in the `AdditionalInfo` only. But not! Even if there are not excluded properties in the container class or struct (in our scenario in the `User` struct) but exist in the contained custom types, then _you have to mandatorily declare the `excludedProperties` array and initialize it in the container structure, without adding any content to it_.\r\n\r\nThat means that even if we wouldn’t have any properties to exclude in the `User` struct, we would still need to declare the following without adding any values:\r\n\r\n```swift\r\nvar excludedProperties = [String]() \r\n```\r\n\r\nA GTCodable-conforming custom type can contain collections or dictionaries with GTCodable-conforming types as well. Consider the following array in the `User` struct:\r\n\r\n```swift\r\nstruct User: GTCodable {\r\n    // Other property declarations\r\n\r\n    var buddies: [User]?\r\n}    \r\n```\r\n\r\nLet’s add a couple of buddies to our `user` object:\r\n\r\n```swift\r\nvar user = User()\r\n// Other User property configuration here\r\n\r\nvar batman = User(id: 15, username: \"batman\", email: \"batman@superheroes.org\", avatarFile: \"batman.png\")\r\nbatman.additionalInfo = AdditionalInfo(firstName: \"Bruce\", lastName: \"Wayne\", gender: .male)\r\n\r\nvar spiderman = User(id: 21, username: \"spiderman\", email: \"spiderman@superheroes.org\", avatarFile: \"spiderman.png\")\r\nspiderman.additionalInfo = AdditionalInfo(firstName: \"Peter\", lastName: \"Parker\", gender: .male)\r\n\r\nuser.buddies = [batman, spiderman]    \r\n```\r\n\r\nLet’s JSON encode and see the results:\r\n\r\n    {\r\n      \"additionalInfo\" : {\r\n        \"firstName\" : \"Clark\",\r\n        \"gender\" : 1\r\n      },\r\n      \"buddies\" : [\r\n        {\r\n          \"additionalInfo\" : {\r\n            \"firstName\" : \"Bruce\",\r\n            \"gender\" : 1\r\n          },\r\n          \"email\" : \"batman@superheroes.org\",\r\n          \"id\" : 15,\r\n          \"username\" : \"batman\"\r\n        },\r\n        {\r\n          \"additionalInfo\" : {\r\n            \"firstName\" : \"Peter\",\r\n            \"gender\" : 1\r\n          },\r\n          \"email\" : \"spiderman@superheroes.org\",\r\n          \"id\" : 21,\r\n          \"username\" : \"spiderman\"\r\n        }\r\n      ],\r\n      \"email\" : \"superman@superheroes.org\",\r\n      \"id\" : 11,\r\n      \"username\" : \"superman\"\r\n    }\r\n    \r\n\r\nNotice that the properties that should be ignored are actually excluded from the final outcome.\r\n\r\nEven though all previous examples contains structs only, the exact same principles and techniques apply to classes too!\r\n\r\nOther Features\r\n--------------\r\n\r\nThe most important and vital functions of the GTCodable protocol have been already presented and explained. However, GTCodable comes with a few more additional, auxiliary, let’s say \"bonus\" functions that can make our work a little bit faster.\r\n\r\nWe have already seen the first one; it’s the `getTextualRepresentation(fromJson:)` and returns a textual representation of a JSON object. You can use it with any JSON encoded object, not only those you create with GTCodable.\r\n\r\nThe next one is called `getDocDirPath()`. It returns the path to the documents directory as a String value. If your custom types conform to GTCodable, then you get that path for free and you don’t have to specify it again by yourself.\r\n\r\nThe `getRaw()` function returns the raw value of an enum (or more generally, a _RawRepresentable_ type) as `Any?` type. If no raw value exists, it just returns `nil`. If it doesn’t make any sense to you because we can use the `rawValue` property to get the enum value, you’re right. However, it’d be impossible to get an enum’s value without it while using Reflection.\r\n\r\nLastly, it’s the `describeSelf()` function. This one returns a String value that lists an object’s properties and their values. Take for example the `user` object of the `User` struct:\r\n\r\n```swift\r\nprint(user.describeSelf())    \r\n```\r\n\r\nHere’s what is printed in Xcode console:\r\n\r\n    id: Optional(11)\r\n    username: Optional(\"superman\")\r\n    email: Optional(\"superman@superheroes.org\")\r\n    avatarFile: Optional(\"superman.png\")\r\n    additionalInfo: Optional(GTCodableApp.AdditionalInfo(firstName: Optional(\"Clark\"), lastName: Optional(\"Kent\"), gender: Optional(GTCodableApp.AdditionalInfo.Gender.male), excludedProperties: Optional([\"lastName\"])))\r\n    buddies: Optional([GTCodableApp.User(id: Optional(15), username: Optional(\"batman\"), email: Optional(\"batman@superheroes.org\"), avatarFile: Optional(\"batman.png\"), additionalInfo: Optional(GTCodableApp.AdditionalInfo(firstName: Optional(\"Bruce\"), lastName: Optional(\"Wayne\"), gender: Optional(GTCodableApp.AdditionalInfo.Gender.male), excludedProperties: nil)), buddies: nil, excludedProperties: nil), GTCodableApp.User(id: Optional(21), username: Optional(\"spiderman\"), email: Optional(\"spiderman@superheroes.org\"), avatarFile: Optional(\"spiderman.png\"), additionalInfo: Optional(GTCodableApp.AdditionalInfo(firstName: Optional(\"Peter\"), lastName: Optional(\"Parker\"), gender: Optional(GTCodableApp.AdditionalInfo.Gender.male), excludedProperties: nil)), buddies: nil, excludedProperties: nil)])\r\n    excludedProperties: Optional([\"avatarFile\"])\r\n    \r\n\r\nThe Rules\r\n---------\r\n\r\nPlease follow the next rules for a proper usage of the GTCodable protocol.\r\n\r\n*   Stating the obvious: Classes, structs and enums can conform to GTCodable protocol.\r\n*   When it’s necessary to exclude properties from encoding or conversion, declare a String array in your custom type (class or struct) and name it **excludedProperties** mandatorily.\r\n*   The names of the properties that should be excluded from encoding or conversion must be added to the `excludedProperties` array. Watch out for typos.\r\n*   Properties that should be excluded from encoding and conversion must be declared as _Optionals_. Avoiding doing that will result in failure when trying to load data to an object.\r\n*   Always declare and initialise the `excludedProperties` array if your class or struct contains custom types that conform to GTCodable protocol and the have their own properties that should be ignored.\r\n*   If any problems are met with properties of custom types inside a class or struct that conform to GTCodable protocol, try to initialise them at the time of declaration if possible.\r\n*   Always set an explicit type to Enums that conform to GTCodable.\r\n*   There is no need to adopt the Encodable, Decodable, or Codable Swift protocols when using GTCodable.\r\n*   Tuples are not supported; avoid tuples. Use arrays or dictionaries instead.\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgabrieltheodoropoulos%2Fgtcodable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgabrieltheodoropoulos%2Fgtcodable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgabrieltheodoropoulos%2Fgtcodable/lists"}