{"id":381,"date":"2019-10-22T06:34:03","date_gmt":"2019-10-22T13:34:03","guid":{"rendered":"https:\/\/www.appsdissected.com\/?p=381"},"modified":"2019-10-22T06:50:26","modified_gmt":"2019-10-22T13:50:26","slug":"json-codable-decodingerror-quicktype","status":"publish","type":"post","link":"https:\/\/www.appsdissected.com\/json-codable-decodingerror-quicktype\/","title":{"rendered":"Restoring your sanity reading JSON into Codables"},"content":{"rendered":"\n<p>Integrating your app with APIs means you\u2019re going to be dealing with parsing JSON in data objects you can use nicely. iOS provides the Codable protocol to do just that thing, but once you start trying to map JSON to that well-formed protocol, that\u2019s when things fall apart.<\/p>\n\n\n\n<p>JSON doesn\u2019t have standard schemas (at least none that were ever seriously adopted), so you\u2019re stuck with reading documentation like this for the details:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-attachment-id=\"383\" data-permalink=\"https:\/\/www.appsdissected.com\/json-codable-decodingerror-quicktype\/get-a-project\/\" data-orig-file=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/Get-a-project-\u00a9.png\" data-orig-size=\"687,800\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/Get-a-project-\u00a9-258x300.png\" data-large-file=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/Get-a-project-\u00a9.png\" decoding=\"async\" loading=\"lazy\" width=\"687\" height=\"800\" src=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/Get-a-project-\u00a9.png\" alt=\"\" class=\"wp-image-383\" srcset=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/Get-a-project-\u00a9.png 687w, https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/Get-a-project-\u00a9-258x300.png 258w\" sizes=\"(max-width: 687px) 100vw, 687px\" \/><\/figure>\n\n\n\n<p>\ud83d\ude12 Great, that\u2019s useful\u2026 One example response, no field descriptions, types, anything. (And before you ask, this is the GitHub API documentation, so not even large organizations are immune to this problem.)<\/p>\n\n\n\n<p>So you code your app off of these examples, then when you try and use it in the wild, you get:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-attachment-id=\"384\" data-permalink=\"https:\/\/www.appsdissected.com\/json-codable-decodingerror-quicktype\/underlyingerror-nil-file-jsoncodable-playground-line-101\/\" data-orig-file=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/underlyingError-nil-file-JSONCodable.playground-line-101.png\" data-orig-size=\"1174,150\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"underlyingError nil)) file JSONCodable.playground, line 101\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/underlyingError-nil-file-JSONCodable.playground-line-101-300x38.png\" data-large-file=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/underlyingError-nil-file-JSONCodable.playground-line-101-1024x131.png\" decoding=\"async\" loading=\"lazy\" width=\"1024\" height=\"131\" src=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/underlyingError-nil-file-JSONCodable.playground-line-101-1024x131.png\" alt=\"\" class=\"wp-image-384\" srcset=\"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/underlyingError-nil-file-JSONCodable.playground-line-101-1024x131.png 1024w, https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/underlyingError-nil-file-JSONCodable.playground-line-101-300x38.png 300w, https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/underlyingError-nil-file-JSONCodable.playground-line-101-768x98.png 768w, https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/underlyingError-nil-file-JSONCodable.playground-line-101.png 1174w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>I followed their documentation, and it didn\u2019t work. How the heck am I ever going to figure out how to make this API JSON into a nice, easy to use Swift struct?!<\/strong><\/p>\n\n\n\n<p>Thankfully, there are some tricks \u2014 and one tool \u2014 you can use to make your job a lot easier. We\u2019ll start by deciphering those error messages above, and how to figure out what error they are trying to point out. Then we\u2019ll cover a procedure I like to use whenever I encounter one of these errors to fix them, and even use to avoid these errors in the first place. Let\u2019s dive in.<\/p>\n\n\n\n<!--more-->\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Deciphering the error messages<\/h2>\n\n\n\n<p>First, let\u2019s talk about the error messages and figure out what they\u2019re trying to tell us.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: \"body\", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: \"No value associated with key CodingKeys(stringValue: \\\"body\\\", intValue: nil) (\\\"body\\\").\", underlyingError: nil)): file JSONCodable.playground, line 101<\/pre>\n\n\n\n<p>There\u2019s a lot to unpack in that error message above, and it isn\u2019t the best formatted, but the important bit is in the first part after \u201craised an error\u201d: <strong>Swift.DecodingError.keyNotFound<\/strong>. This tells you that the decoder was expected a value for a particular key, but it wasn\u2019t present. The codingPath tells you where in the JSON the decoding failed \u2014 which in this case, the codingPath is empty, meaning it was looking in the root object \u2014 and the stringValue tells you it was looking for a key \u201cbody\u201d and it was not present.<\/p>\n\n\n\n<p>Just knowing this is the error gives you the solution: the \u201cbody\u201d property in your Codable object is most likely not an Optional, but it should be. Make the one character change from a `String` to a `String?`, and you\u2019ll find your problem is fixed.<\/p>\n\n\n\n<p>So what kind of errors can we run into decoding a JSON? In this case, the Apple documentation helps us out. Note the <strong>Swift.DecodingError<\/strong> in the error message. This is an enum that contains all of the possible error types that a decoder can throw.<\/p>\n\n\n\n<p>You can look at <a href=\"https:\/\/developer.apple.com\/documentation\/swift\/decodingerror\">Apple&#8217;s documentation<\/a> for more information, but I will summarize the short list here:<\/p>\n\n\n\n<p><strong>KeyNotFound:<\/strong><br>I would say this is by far the most common error I see when trying to make Codables from JSON from third-party APIs, because it is usually so difficult to figure out whether a key is going to be required or not. This error is pretty much what it says in the description: your Codable was expecting a value for a particular key, but the key wasn\u2019t found in the JSON object. You can change your key to an Optional type, and that should resolve this.<\/p>\n\n\n\n<p><strong>ValueNotFound:<\/strong><br>Very similar to the keyNotFound error above, this is a case where the key was actually found in the JSON object, but it had a value of \u201cnull,\u201d equivalent to nil in Swift. Because that requires the type to be optional, if the type in your Codable is not optional, you receive this error.<\/p>\n\n\n\n<p><strong>TypeMismatch:<\/strong><br>This error occurs when your Codable has a particular type, but when the decoder was parsing the JSON, it found a value with a different type. This can mean one of two things: you just got the type wrong in your Codable, you fix it, and everything works great. However, because JSON doesn\u2019t have any strict rules about what types values can take on, and no schemas to guide you, you can have a list of JSON objects where the value for \u201ckey1\u201d is a string in one object, a list in the next object, not present in the next object, and a full JSON object in the next one. This is a rare situation, but it does exist, because some API writers really hate their users. You can fix this in your Codable, but let\u2019s leave that solution until the next section, where we\u2019ll have a tool to help out\u2026<\/p>\n\n\n\n<p><strong>DataCorrupted:<\/strong><br>This last error is more of a catch-all error for when the parsing fails because the Decoder can\u2019t parse the JSON. This can either mean the JSON is simply invalid, but there are some specific cases where the JSON itself is valid, but because of how you have configured your JSONDecoder to handle certain value types, such as dates, if the format isn\u2019t strictly matched, the decoder will throw this error.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fixing the problems \u2014 or avoiding them in the first place<\/h2>\n\n\n\n<p>Usually once you run into the errors above, they\u2019re generally easy to fix. But it\u2019s not going to be a very good strategy to just keep throwing data at our Codable until it breaks <strong>again<\/strong>. Plus, JSON being the very loose, schemaless format it is, there\u2019s always the possibility of running into an error above that it isn\u2019t plainly obvious why it\u2019s failing, or how to fix it. This is where having a standard technique for resolving these issues will help you not only fix the problems when you run into them, but avoid them in the first place by applying it from the beginning.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Collect data<\/h3>\n\n\n\n<p>To begin with, in order to find as many of the corner cases as possible, I try and collect as large of a response as I can of the target query. With a large response, I have a better chance of finding all of the corner cases within an API (optional fields, any strangely-typed fields, etc.).<\/p>\n\n\n\n<p>Using the example GitHub project query above, I would search for a complementary query method in the API, because more than likely it is using the same structure. Then I would try a query that returns several hundred records or so. This will provide a representative sample of the JSON data that this API may return, that you would use in the next step later.<\/p>\n\n\n\n<p>In the GitHub example from above, there is a query API available, <a href=\"https:\/\/developer.github.com\/v3\/search\/\">described here<\/a>, that will work nicely. They even provide a sample query that you can use to give you a JSON directly, no API key needed:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">curl https:\/\/api.github.com\/search\/repositories?q=tetris+language:assembly&amp;sort=stars&amp;order=desc<\/pre>\n\n\n\n<p>As of the time of this post, it returns over 1600 results, which is a nice sample size to feed into the next step.<\/p>\n\n\n\n<p>If you cannot find a query API that matches, the process becomes a little harder, because you will need to construct individual queries by hand for individual results, which means finding API IDs. Presumably there is a query that at least returns those, then you can write a script to download those results one by one. The good news is, all of those individual records will still work in the next step.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use QuickType to analyze your result set<\/h3>\n\n\n\n<p><a href=\"https:\/\/www.appsdissected.com\/generate-your-json-object-models-quicktype\/\">In the past<\/a>, I\u2019ve talked about the <a href=\"https:\/\/quicktype.io\/\">quicktype<\/a> tool. As a quick summary, it takes one or more JSON objects as an input, and will produce code for an object model in a number of different languages, including Swift and Objective-C. This is what we will use to feed our data into. Let\u2019s continue with the GitHub example.<\/p>\n\n\n\n<p>I definitely recommend you follow along with the steps using the online version at <a href=\"https:\/\/app.quicktype.io\">https:\/\/app.quicktype.io<\/a>, because the results are too big to include here.<\/p>\n\n\n\n<p>First, access the URL example above for the GitHub projects list: <a href=\"https:\/\/api.github.com\/search\/repositories?q=tetris+language:assembly&amp;sort=stars&amp;order=desc\">https:\/\/api.github.com\/search\/repositories?q=tetris+language:assembly&amp;sort=stars&amp;order=desc<\/a>. This will return a JSON; select all of it using Cmd+A, and copy with Cmd+C<\/p>\n\n\n\n<p>Now, pull up <a href=\"https:\/\/app.quicktype.io\">https:\/\/app.quicktype.io<\/a>. In the left pane select the JSON that\u2019s there in the example to remove it, and Cmd+V paste in your GitHub JSON. The right pane code will change, and will now contain an object model that matches the sample you entered into the left pane.<\/p>\n\n\n\n<p>When you investigate the model, you\u2019ll even notice that it has attempted to apply some smarts to the object model: detecting fields that look like dates and making them Date fields, and even finding string fields that have limited sets of values and converting them into Swift enums. It\u2019s really quite a great tool.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Use wholesale, or extract the bits you need<\/h3>\n\n\n\n<p>The easiest thing to do, of course, is take quicktype\u2019s model and use it as is. It\u2019s often the thing I do after reviewing it to make sure it looks good.<\/p>\n\n\n\n<p>If you are correcting an existing object model, or the parsing you need to do doesn\u2019t require a full object model, you may only want to pull a couple of pieces out of the code and integrate into your object model. The best thing to do is review the entire object model, look at the quicktype result for any surprises (like unexpected optional fields, strange types, etc.), and copy over the bits you need that don\u2019t match up with what you originally wrote.<\/p>\n\n\n\n<p>There is one final thing to mention about the model quicktype returns. As already mentioned multiple times, JSON is a freeform data format, and values can take on different types. Values in objects can be any type, values in list can be any type, etc. This means that sometimes quicktype returns code like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>enum HasWiki: Codable {\n    case bool(Bool)\n    case integer(Int)\n\n\u00a0 \u00a0 init(from decoder: Decoder) throws {\n\u00a0 \u00a0 \u00a0 \u00a0 let container = try decoder.singleValueContainer()\n\u00a0 \u00a0 \u00a0 \u00a0 if let x = try? container.decode(Bool.self) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self = .bool(x)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 if let x = try? container.decode(Int.self) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self = .integer(x)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 throw DecodingError.typeMismatch(HasWiki.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"Wrong type for HasWiki\"))\n\u00a0 \u00a0 }\n\n\u00a0 \u00a0 func encode(to encoder: Encoder) throws {\n\u00a0 \u00a0 \u00a0 \u00a0 var container = encoder.singleValueContainer()\n\u00a0 \u00a0 \u00a0 \u00a0 switch self {\n\u00a0 \u00a0 \u00a0 \u00a0 case .bool(let x):\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 try container.encode(x)\n\u00a0 \u00a0 \u00a0 \u00a0 case .integer(let x):\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 try container.encode(x)\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 }\n}<\/code><\/pre>\n\n\n\n<p>In this case, I forced this particular situation happen by changing one of the \u201chasWiki\u201d boolean values in the sample data into an integer. This meant that hasWiki can either be a Bool or an Int. quicktype detects that from the sample, and generates this helper enum that acts as a container for both of those values, and gives you all of the code you need to encode\/decode those values. It does more than just give you an object model; it manages all of those weird corner cases, giving you something easy, even for the weirdest of JSON. I suggest you give it a try the next time you run into JSON decoding errors.<br><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Integrating your app with APIs means you\u2019re going to be dealing with parsing JSON in data objects you can use nicely. iOS provides the Codable<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/www.appsdissected.com\/json-codable-decodingerror-quicktype\/\">Read on \u00bb<span class=\"screen-reader-text\">Restoring your sanity reading JSON into Codables<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":388,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_newsletter_tier_id":0,"footnotes":""},"categories":[12,24],"tags":[],"jetpack_featured_media_url":"https:\/\/www.appsdissected.com\/wp-content\/uploads\/2019\/10\/Apps-Dissected-Featured-Image-JSON-into-Codables-1.png","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pamuk3-69","jetpack-related-posts":[{"id":38,"url":"https:\/\/www.appsdissected.com\/generate-your-json-object-models-quicktype\/","url_meta":{"origin":381,"position":0},"title":"Got JSON? Need objects? Stop typing, and start generating your object models with Quicktype","author":"Evan","date":"November 3, 2018","format":false,"excerpt":"It's time to integrate another API into your app. That statement alone brings all these feelings to mind: Poring over the API documentation, teasing out the JSON requests and responses for each call you need to use Extracting a schema out of those requests and responses, being mindful of the\u2026","rel":"","context":"In &quot;Backend&quot;","block_context":{"text":"Backend","link":"https:\/\/www.appsdissected.com\/category\/backend\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2018\/11\/Screen-Shot-2018-11-03-at-10.07.49-1024x915.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2018\/11\/Screen-Shot-2018-11-03-at-10.07.49-1024x915.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2018\/11\/Screen-Shot-2018-11-03-at-10.07.49-1024x915.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2018\/11\/Screen-Shot-2018-11-03-at-10.07.49-1024x915.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":248,"url":"https:\/\/www.appsdissected.com\/manual-app-badge-tutorial\/","url_meta":{"origin":381,"position":1},"title":"Adding manual app badges to your app: step by step","author":"Evan","date":"April 18, 2019","format":false,"excerpt":"It\u2019s really common for apps that support notifications to use them to update the application badge to display numbers of unread messages, undone tasks, etc. But what if you don\u2019t need or want the added complexity of supporting push notifications, or even local notifications, but want to alert the user\u2026","rel":"","context":"In &quot;UIKit&quot;","block_context":{"text":"UIKit","link":"https:\/\/www.appsdissected.com\/category\/uikit\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/04\/Apps-Dissected-Featured-Image-Manual-App-Badges.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/04\/Apps-Dissected-Featured-Image-Manual-App-Badges.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/04\/Apps-Dissected-Featured-Image-Manual-App-Badges.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/04\/Apps-Dissected-Featured-Image-Manual-App-Badges.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/04\/Apps-Dissected-Featured-Image-Manual-App-Badges.png?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":157,"url":"https:\/\/www.appsdissected.com\/port-objective-c-swift-extensions-3\/","url_meta":{"origin":381,"position":2},"title":"Porting to Swift? Do it Gradually Using Extensions: Part 3","author":"Evan","date":"February 8, 2019","format":false,"excerpt":"As a refresher from Part 1 and Part 2, we\u2019re trying to make the process of porting Objective-C to Swift code more gradual by porting classes method by method using Swift extensions. This is very helpful in keeping with the idea of \u201cWhen it comes to porting, smaller steps are\u2026","rel":"","context":"In &quot;Swift&quot;","block_context":{"text":"Swift","link":"https:\/\/www.appsdissected.com\/category\/swift\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default.jpg?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":172,"url":"https:\/\/www.appsdissected.com\/uitableviewcell-data-delegates\/","url_meta":{"origin":381,"position":3},"title":"How Do You Get the Data From Your Custom UITableViewCells?","author":"Evan","date":"February 15, 2019","format":false,"excerpt":"You don\u2019t need to progress very far into iOS development before you need to deal with tables. This means: UITableView, and probably your own custom UITableViewCells. A common pattern is to have editable controls in those cells, so that the user can change data from the table itself. Now you\u2019re\u2026","rel":"","context":"In &quot;UIKit&quot;","block_context":{"text":"UIKit","link":"https:\/\/www.appsdissected.com\/category\/uikit\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default-1.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default-1.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default-1.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default-1.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/02\/stencil.default-1.jpg?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":84,"url":"https:\/\/www.appsdissected.com\/which-ios-architecture-pattern-to-start-with\/","url_meta":{"origin":381,"position":4},"title":"MVC? MVVM? VIPER? Which iOS architecture do I start with?","author":"Evan","date":"November 19, 2018","format":false,"excerpt":"When you're investigating iOS development, early on you will run into discussions about iOS app architectures, and start getting hit with a wall of acronyms and jargon: MVC, MVVM, MVP, VIPER, RIBS, Clean, RxSwift, ReactiveCocoa, and even more. You will also find heated discussions online where developers sing the praises\u2026","rel":"","context":"In &quot;Architecture&quot;","block_context":{"text":"Architecture","link":"https:\/\/www.appsdissected.com\/category\/architecture\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2018\/11\/Model-Graphic.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2018\/11\/Model-Graphic.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2018\/11\/Model-Graphic.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2018\/11\/Model-Graphic.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2018\/11\/Model-Graphic.png?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":324,"url":"https:\/\/www.appsdissected.com\/getting-ready-swiftui-combine\/","url_meta":{"origin":381,"position":5},"title":"4 things you can do *right now* to be ready for SwiftUI and Combine","author":"Evan","date":"August 5, 2019","format":false,"excerpt":"Many of us were excited about all the new frameworks at WWDC: SwiftUI and Combine being the biggest ones. You were probably all ready to start using them in your app, until you opened up the documentation and saw this: And you felt at least one of these feelings: \ud83d\ude21\u2026","rel":"","context":"In &quot;Architecture&quot;","block_context":{"text":"Architecture","link":"https:\/\/www.appsdissected.com\/category\/architecture\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/08\/Apps-Dissected-Featured-Image-SwiftUI-and-Combine-4-Things.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/08\/Apps-Dissected-Featured-Image-SwiftUI-and-Combine-4-Things.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/08\/Apps-Dissected-Featured-Image-SwiftUI-and-Combine-4-Things.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/08\/Apps-Dissected-Featured-Image-SwiftUI-and-Combine-4-Things.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/www.appsdissected.com\/wp-content\/uploads\/2019\/08\/Apps-Dissected-Featured-Image-SwiftUI-and-Combine-4-Things.png?resize=1050%2C600&ssl=1 3x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/posts\/381"}],"collection":[{"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/comments?post=381"}],"version-history":[{"count":0,"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/posts\/381\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/media\/388"}],"wp:attachment":[{"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/media?parent=381"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/categories?post=381"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appsdissected.com\/wp-json\/wp\/v2\/tags?post=381"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}