{"componentChunkName":"component---src-templates-legacy-tutorial-page-js","path":"/oa/tutorials/product-hunt-api-tutorial/update-view-controllers/","result":{"pageContext":{"tutorial":{"id":"T0E6OlR1dG9yaWFsLTE3MQ==","slug":"product-hunt-api-tutorial","title":"Product Hunt API Tutorial","previewText":"A client wants to build a simple wrapper around Product Hunt.s\n","heroImagePath":"https://raw.githubusercontent.com/MakeSchool-Tutorials/Product-Hunt-API-Tutorial/master/cover.png","heroImageFile":{"childImageSharp":{"gatsbyImageData":{"layout":"constrained","placeholder":{"fallback":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAD6ElEQVQ4y42RX0xcRRTGLwu+YKxGk1ZD60N3Gl7qCwoxmmqkaGO0aXzQxNYHHzSxPmliNBqNYrVWU+auRYnWSA1SoYFuNPhQ2vLn3pUWUigiKBQKhYXddZe1bFl22b33zvnMzN1rtm2aOMnkzJw553e+c0YDkZZzRAkAuTVB9AkRrViOiIAoBhRvxIgoZjkiCqKkI8SrMgdA6T9ZSyMi7ToYgE+JCAAhmbVRP7iMdwcSeG8ggZe6w9jdNY83jSiylgMSQsUBeKUYqhXDImkLx/5MOQAJgKh/MUN1wUV65MQ83fbVBG1pnqILsYyqmM7ZzuHQHK6tW9dBNQ+2mnew71TUecuMq7JZy1H2YnwdO0+G8UDrNGaurksXcrYg2cmO7wbFC22jcJRaF6pg0TUL+3v/FjXtC/Th+WX5SN/8kUTH9IoChJbWMJbIqnPrZAq/RTIqZk/rCG6vPy1e7hzD1UxeQSUw8svsKh4+sWDVBRfx/rll1dLBC3GUN02gL5yGt7rm0jIOxpILfPbHYdr8RS/uOnAm1z+XlL5+zXKoGsBqy2QKVT/N2x+ccxXqo8vkaxzH5uZJ9ITT6F7IoC4YxmMdYalQFX2mZRgbPj5tdYxHZc5Mat26vzBDF/r12AreMOK2fG0YSVB50wTdc/QvbG+Zws72GezuiuLxjgVygYQnvh+yjo0syvDLa3m7wpthWeFjqgXR6nBczcoOjC6jtHGcqtrm6KnOK9imm6htn6ba4BINqBkKazCsZnw574iKAqPM+2UFJZJKSQ3t0HDC3tJ8Cc/9GqFdJ+eJcYMqdYOqW6bQv5S1CmOdXcs7FcUMzXEcr23lSGYd1f7P7kfZe7oieLLzClUGTNp6uA/3ft5njcbWlLKpZKbiBkGqZQUVQkiHehDCnem34yvY0RG2nw7Oq5Y3HuyxWkeXFOxazlUmcyRIbqVQLnnxoJ5SOVMA6aMTKdQcn7XvO9TrwWZzDv2nzIMpdcXLgxa3AHKVNo4k8MPFiFKWyORvavMmWDHUtm+Agh4CkAJwKWs5/x92C2iptFlbbF3JWpuKfbeEMW74GDel1Rg3S+T9bApa+Ufd2oYDZ3zHf4+U5QsFmgYXyk5NJ7TKgOlTeYEBmVfq50Ypc7fPA8ntY3rIvQeGpC3xc0Or1E2tvnemTHvwiDpv01WiG/fleWX93p0bUqG5l+mhOxVMD93NuPkiOzJUUii0l3HzUVVQD21k3HzeTTZrGTdeY4GBOxg33mHc+IxxQ5e5khpj3GjzN/TJc5BxI+Jv6JGATYW3s37eL+9V8sy4uY9xY4Rxs4bpoe2MG3N+brzu58bbjBu7/gWOSk/VhPcKJgAAAABJRU5ErkJggg=="},"images":{"fallback":{"src":"/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/5aead/cover.png","srcSet":"/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/e9fba/cover.png 50w,\n/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/15e42/cover.png 100w,\n/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/5aead/cover.png 200w,\n/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/d6138/cover.png 400w","sizes":"(min-width: 200px) 200px, 100vw"},"sources":[{"srcSet":"/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/b79cb/cover.avif 50w,\n/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/6d0de/cover.avif 100w,\n/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/f2685/cover.avif 200w,\n/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/4ff31/cover.avif 400w","type":"image/avif","sizes":"(min-width: 200px) 200px, 100vw"},{"srcSet":"/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/dbc4a/cover.webp 50w,\n/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/d8057/cover.webp 100w,\n/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/2e34e/cover.webp 200w,\n/mediabook/static/a69ceb219f4e17b4f09e707a84068da8/416c3/cover.webp 400w","type":"image/webp","sizes":"(min-width: 200px) 200px, 100vw"}]},"width":200,"height":200}}},"pages":{"nodes":[{"id":"T0E6OlBhZ2UtMTYyNg==","title":"Get Started.","slug":"getting-started","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tODE4OA==","title":"Get Started.","htmlContent":"<p>You just got hired to develop an app that shows the currently featured apps on <a href=\"https://producthunt.com\" target=\"_blank\">Product Hunt</a> &#127881;</p><p>The first feature the client wants you to implement is the feed, which displays all of today's featured products on Product Hunt. The goal for this tutorial is to build a <strong>quick prototype</strong> to show the client all the core features in action.</p>"},{"id":"T0E6OlNlY3Rpb24tODE4OQ==","title":"Why is this important?","htmlContent":"<p>You'll want the app you're building to interact with APIs, or be able to communicate with them, then you need to know how to build a Network Layer, as well as how to code/decode data from APIs to your app and vice versa. This is common functionality that iOS engineers should expect to do in their careers, so learning the fundamentals around it now will make you that much more prepared for that upcoming gig.</p>"},{"id":"T0E6OlNlY3Rpb24tODE5MA==","title":"Learning Outcomes","htmlContent":"<p>By the end of this tutorial, you should be able to:</p><ol>\n<li>Work with APIs interacting with an iOS app.</li>\n<li>Build a Network Layer in Swift.</li>\n<li>Decode JSON into Swift models.</li>\n<li>Take advantage of mock data.</li>\n<li>Display data in tableviews with custom UI.</li>\n</ol>"},{"id":"T0E6OlNlY3Rpb24tODE5MQ==","title":"Technical Planning","htmlContent":"<p>Here's what we need to do to get this feed up and running:</p><ol>\n<li>Inspect the Product Hunt API</li>\n<li>Build the Feed View</li>\n<li>Create the Post Model</li>\n<li>Build the Post Cell</li>\n<li>Create the Post Cell Class</li>\n<li>Test the Feed Table View</li>\n<li>Allow the Post Model to work with network requests</li>\n<li>Create the network layer</li>\n<li>Retrieve data from the PH API</li>\n<li>Build the Comments View</li>\n<li>Pull Comments data from the API</li>\n<li>Update the view controllers to hook everything up</li>\n</ol>"},{"id":"T0E6OlNlY3Rpb24tODE5Mg==","title":"What We're Building","htmlContent":"<p>Here's what the prototype app will look like:</p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P00-Getting-Started/assets/01_what-were-building_final-product.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P00-Getting-Started/assets/01_what-were-building_final-product.png\" alt=\"Preview final product\" title=\"\">\n        </a></p><h2>User Stories</h2><p><strong>As a user...</strong></p><ul>\n<li>I can browse products featured today on Product Hunt by scrolling through the app's main screen.</li>\n<li>I see each product's name, tagline, number of votes.</li>\n<li>I can tap on each post to see its comments in descending order.</li>\n</ul>"},{"id":"T0E6OlNlY3Rpb24tODE5Mw==","title":"Implementation Plan","htmlContent":"<p>We're going to start with the UI of the app and then moving on to the networking layer.</p><p>This makes it quick and easy to build out the app and test some of its features before making requests to the API.</p>"},{"id":"T0E6OlNlY3Rpb24tODE5NA==","title":"Using Git/GitHub","htmlContent":"<p>As you go through this tutorial, you will also be making commits after completing milestones. <strong>This is a requirement, you must make a commit whenever the tutorial prompts you</strong>. This not only further enforces best practices for software engineering, but also will help you more easily figure out where a bug originated from if you break your progress up into discrete, trackable chunks.</p><p>When prompted to commit, you'll see a sample commit message. Feel free to use your own message, so long as it clearly and concisely covers the work done.</p><p>Lastly, the commit prompts in this tutorial should be the <strong>minimum</strong> amount of times you commit. If you want to do more commits, breaking your chunks into even smaller chunks, that is totally fine!</p>"}]},"next":{"id":"T0E6OlBhZ2UtMTYyNw==","slug":"product-hunt-api","title":"Inspecting The Product Hunt API"},"previous":{"id":"T0E6OlBhZ2UtMTYyNw==","slug":"product-hunt-api","title":"Inspecting The Product Hunt API"}},{"id":"T0E6OlBhZ2UtMTYyNw==","title":"Inspecting The Product Hunt API","slug":"product-hunt-api","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzE1Mg==","title":"Inspecting The Product Hunt API","htmlContent":"<p>Product Hunt is an amazing platform to discover new apps and projects. We'll be making it much easier to discover the best ones that have been released recently.</p>"},{"id":"T0E6OlNlY3Rpb24tNzE1Mw==","title":"Checkout Product Hunt","htmlContent":"<p>You will need to sign up for Product Hunt, register an application, and generate the token needed to use the API in our app.</p><p>When you get the chance, explore the Product Hunt for cool projects and ideas.</p><div class=\"action\">\n<p>\nGo to <a href=\"https://www.producthunt.com/\" target=\"_blank\">Product Hunt</a> and create an account.</p>\n\n<p>If you already have a Product Hunt account then navigate to the <code>API Dashboard</code> from the drop-down menu under your account tab.</p>\n</div><p>With an account created you can now register an application, which will allow us to access the API.</p><div class=\"action\">\n<p>\nCheck out the <a href=\"https://api.producthunt.com/v1/docs/\" target=\"_blank\">API docs</a>; this gives you all the information you need to use the API.</p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE1NA==","title":"Create An Application","htmlContent":"<p>In order to use the API, we'll have to register our application in the API Dashboard</p><p>From the API Docs page,</p><div class=\"action\">\n<p>\nClick the link at top right labeled \"API Dashboard\" to navigate to the API Dashboard.</p>\n\n<p>Click on <em>ADD AN APPLICATION</em>.</p>\n\n<p>Give your application a name and the following redirect URI:\n<code>https://localhost:3000/users/auth/producthunt/callback</code></p>\n\n<p>Click on <em>CREATE APPLICATION</em> to create the application</p>\n\n<p>On the same page click <em>CREATE TOKEN</em> to generate the access token you'll use later in this tutorial. Keep this page open for later use.</p>\n\n<p>Your dashboard should now look similar to this:\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P01-Inspecting-The-Product-Hunt-API/assets/01_create-an-app_api-dashboard.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P01-Inspecting-The-Product-Hunt-API/assets/01_create-an-app_api-dashboard.png\" alt=\"API dashboard\" title=\"\">\n        </a></p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE1NQ==","title":"Make a GET Request with Postman","htmlContent":"<p>Now that we have access to the API, let's check out the structure of the data we'll be receiving. To do this, we'll use Postman.</p><p>Postman is an API Development Environment (ADE) and an awesome tool for any developer working with APIs. We'll be using it in this tutorial to test making requests to the Product Hunt API and analyze the data we get to model the data in Swift.</p><div class=\"action\">\n<p>\nDownload the <a href=\"https://www.getpostman.com/\" target=\"_blank\">Postman desktop app</a> from their website if you don't have it already. You don't need an account to use it.</p>\n</div><p>Upon opening Postman, you should see this welcome screen:\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P01-Inspecting-The-Product-Hunt-API/assets/02_make-a-get_postman-welcome.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P01-Inspecting-The-Product-Hunt-API/assets/02_make-a-get_postman-welcome.png\" alt=\"Postman welcome screen\" title=\"\">\n        </a></p><p>If you don't immediately see this screen, you can navigate to it by clicking on the <em>+ NEW</em> button located towards the top of the screen.</p><div class=\"action\">\n<p>\nChoose <strong>Request</strong> under building blocks to create a new request called <strong>GET Posts</strong> and save it a new collection called <strong>Product Hunt</strong>.\nAfter clicking <em>+ SAVE</em> you'll be brought to the homepage. Paste this URL into the URL field at the top of the window: <code>https://api.producthunt.com/v1/posts/all?sort_by=votes_count&amp;order=desc&amp;search[featured]=true&amp;per_page=20</code></p>\n</div><p>Let's break down the URL into the important pieces so that we know what's actually going on during this call:</p><ul>\n<li>\n<code>api.producthunt.com/v1</code> is the <strong>base URL</strong> for this API.  Think of this as the common prefix to use while navigating throughout the API.</li>\n<li>\n<code>posts/all</code> is the <strong>endpoint</strong> or <strong>route</strong> which gives you access to every product posted on Product Hunt (as long as you have a valid token!).</li>\n<li>Everything after the <strong><em>?</em></strong> are the <strong>parameters</strong> of our request and each parameter is separated by an <strong><em>&amp;</em></strong>.</li>\n<li>\n<code>sort_by=votes_count</code> and <code>order=desc</code> denotes that we want the resulting data to be organized by the number of votes in descending order.</li>\n<li>\n<code>search[featured]=true</code> makes it so that we only get featured posts.</li>\n<li>\n<code>per_page=20</code> limits the amount of posts we get to only 20. There are thousands of products listed on product hunt, we'll only need to get 20 at a time for our app.</li>\n</ul><p>Lastly, we need to include our access token in our request. You can find your token key from the same site as earlier located under the <strong>Developer Token</strong> section from when you last clicked <em>CREATE TOKEN</em> on the API Dashboard on Product Hunt.  </p><p>Under <em>Authorization</em>, select <strong>Bearer Token</strong> in the drop down and paste your access token. Be sure to hit <em>Preview Request</em>.</p><div class=\"action\">\n<p>\nHit send. You should receive is the data from Product Hunt as a response to your request. This is what you should see:</p>\n\n<p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P01-Inspecting-The-Product-Hunt-API/assets/03_make-a-get_postman-get.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P01-Inspecting-The-Product-Hunt-API/assets/03_make-a-get_postman-get.png\" alt=\"JSON response\" title=\"\">\n        </a></p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE1Ng==","title":"Analyzing the Response","htmlContent":"<p>What you received from your request is known as <strong>JSON (Javascript Object Notation)</strong>, a text format that is completely language independent and easy to read.</p><p>How the data in the JSON response is organized is extremely important, especially for our app. We'll need to understand the hierarchy of the data so that we can accurately model the data in Swift.</p><p><strong>See if you can find a product's name, tagline, number of votes, and screenshot URL.</strong> Take note of where these are located:</p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P01-Inspecting-The-Product-Hunt-API/assets/04_analyze-response_structure.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P01-Inspecting-The-Product-Hunt-API/assets/04_analyze-response_structure.png\" alt=\"Structure of response\" title=\"\">\n        </a></p><p>The beginning of the JSON response objects is indicated by the opening bracket <code>{</code> and ends with the closing bracket <code>}</code> on the same level. This object only contains one object which is an array of <code>posts</code>, where we will get all the information we need to display today's featured posts on our app.</p><p>The <code>posts</code> array contains the products that match the parameters given in our request. We asked for 20 of today's featured products in descending order of vote count, so we received an array with the first post being today's featured product with the highest votes.</p><p>The properties of the post object also have a hierarchy of objects. We are only interested in <code>comments_count</code>, <code>id</code>, <code>name</code>, <code>tagline</code>, and <code>screenshot_url</code>. You can search up these terms in Postman by using the shortcut <code>CMD + F</code> and typing the name of the property in the search field that appears.</p><p>Take some time to look through Postman and see what's in the API response. This is the very beginning of learning <strong>how to work with APIs</strong></p>"}]},"next":{"id":"T0E6OlBhZ2UtMTYyOA==","slug":"build-feed-view","title":"Building the Feed View"},"previous":{"id":"T0E6OlBhZ2UtMTYyOA==","slug":"build-feed-view","title":"Building the Feed View"}},{"id":"T0E6OlBhZ2UtMTYyOA==","title":"Building the Feed View","slug":"build-feed-view","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tMTIwOTM=","title":"Building the Feed View","htmlContent":"<p>In order to avoid context switching and to reduce development time, we'll be building this app starting with the UI and layout of the app, and then ending with the networking layer.</p><p><strong>Your first goal should be to get a working prototype</strong>. The client wants the feed screen working first, so let's start with that.</p>"},{"id":"T0E6OlNlY3Rpb24tMTIwOTQ=","title":"Project Setup with Xcode","htmlContent":"<p>Create a new Single View App. Check that the <strong>Language</strong> is set to Swift and the <strong>User Interface</strong> is set to Storyboard.</p><p>When you are building prototypes, it's very useful to use Storyboards (If you are using UIKit). You can put together a working app with simple constraints in minutes. Try to resist the temptation to make complex or good looking UI this early, it might only slow you down. You'll get an opportunity later on to polish and upgrade the app to your liking.</p><p>For now you do not need to check any of the boxes like Core Data or UITests for this tutorial.</p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/00_new-project.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/00_new-project.png\" alt=\"Preview Create New Project\" title=\"\">\n        </a></p><p>We'll name the project <strong>Product Hunt Example</strong> but feel free to name it as you please.</p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/00_project-details.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/00_project-details.png\" alt=\"Preview New Project Details\" title=\"\">\n        </a></p>"},{"id":"T0E6OlNlY3Rpb24tMTIwOTU=","title":"Creating the Main Screen","htmlContent":"<p>The <code>FeedView</code> consists of a table view with custom cells that display information about products retrieved from Product Hunt.</p><p>The UI itself is simple, for now let's just build the UI and connect it to a Swift file.</p><p><strong>By the end of Part 4, here's what our storyboard will look like:</strong></p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/01_creating-the-main_feedview-preview.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/01_creating-the-main_feedview-preview.png\" alt=\"Preview FeedView\" title=\"\">\n        </a></p><p>This view is intentionally simple so that we can get it up and running fast.</p><p>We'll be using a navigation controller for this app.</p><!-- --><div class=\"info\">\n<p>\nA navigation controller is a container view controller that manages one or more child view controllers in a navigation interface.\nYou'll get more exposure to this</p>\n</div><!-- --><div class=\"action\">\n<p>\nOpen <code>Main.storyboard</code> and click on the View Controller located within the View Controller Scene.</p>\n</div><p>A shortcut for adding a navigation controller in storyboard is to <strong>embed</strong> a view-controller in one.</p><div class=\"action\">\n<p>\nOn the menu bar select <code>Editor</code>, then <code>Embed in</code> and finally <code>Navigation Controller</code> to quickly wrap the view controller in a navigation controller.\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/02_creating-the-main_embed-controller.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/02_creating-the-main_embed-controller.png\" alt=\"Embedded controller\" title=\"\">\n        </a></p>\n\n<p>Select the <code>Navigation Item</code> under the <code>View Controller Scene</code> and  set the <code>Navigation Item</code>'s title to <code>Feed</code>.\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/03_creating-the-main_nav-item-title.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/03_creating-the-main_nav-item-title.png\" alt=\"Set title\" title=\"\">\n        </a></p>\n</div><p>A perk of keeping things simple in the beginning is that you don't have to spend a lot of time configuring the UI.</p><div class=\"action\">\n<p>\nAdd a table view to the view controller, name it <strong>Feed Table View</strong>, and pin it to all 4 sides.\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/04_creating-the-main_pin-table-view.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/04_creating-the-main_pin-table-view.png\" alt=\"Add table view\" title=\"\">\n        </a></p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tMTIwOTY=","title":"Prepare the Swift file","htmlContent":"<p>To adhere to good coding conventions, rename the <code>ViewController.swift</code> to <code>FeedViewController.swift</code> to better reflect what it's used for.</p><div class=\"action\">\n<p>\nChange the name in the file inspector, for the class, and in the comments at the top of your file.\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/05_prepare-the-swift_rename-viewcontroller.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/05_prepare-the-swift_rename-viewcontroller.png\" alt=\"Rename view controller\" title=\"\">\n        </a></p>\n\n<p>We don't have any data yet, but let's add the functions that we'll be using to update cells.</p>\n\n<p>Add an <strong>extension</strong> for UITableViewDataSource at the bottom of <code>FeedViewController</code> to separate code needed to fill the table view with data.</p>\n<pre><span class=\"kd\">class</span> <span class=\"nc\">FeedViewController</span><span class=\"p\">:</span> <span class=\"bp\">UIViewController</span> <span class=\"p\">{</span>\n  <span class=\"p\">...</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// </span><span class=\"cs\">MARK:</span><span class=\"c1\"> UITableViewDataSource</span>\n<span class=\"kd\">extension</span> <span class=\"nc\">FeedViewController</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewDataSource</span> <span class=\"p\">{</span>\n   <span class=\"c1\">/// Determines how many cells will be shown on the table view.</span>\n   <span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">numberOfRowsInSection</span> <span class=\"n\">section</span><span class=\"p\">:</span> <span class=\"nb\">Int</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Int</span> <span class=\"p\">{</span>\n       <span class=\"k\">return</span> <span class=\"mi\">3</span>\n   <span class=\"p\">}</span>\n\n   <span class=\"c1\">/// Creates and configures each cell.</span>\n   <span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">cellForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n       <span class=\"k\">return</span> <span class=\"bp\">UITableViewCell</span><span class=\"p\">()</span>\n  <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><!-- --><div class=\"info\">\n<p>\nExtensions add new functionality to an existing <code>class</code>, <code>struct</code>, <code>enum</code>, or <code>protocol</code> type.\nThis includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling).</p>\n</div><!-- --><div class=\"action\">\n<p>\nAdd an <strong>extension</strong> for <code>UITableViewDelegate</code> right below that.</p>\n<pre><span class=\"p\">...</span>\n\n<span class=\"c1\">// </span><span class=\"cs\">MARK:</span><span class=\"c1\"> UITableViewDelegate</span>\n<span class=\"kd\">extension</span> <span class=\"nc\">FeedViewController</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewDelegate</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// Code to handle cell events goes here...</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>We'll use this later to setup selecting and deleting cells.</p><div class=\"action\">\n<p>\nOpen your <code>Main.storyboard</code> file and locate the Feed View within the Feed Scene of your file structure. In the identity inspector, update the view's class from <code>View Controller</code> to <code>FeedViewController</code>.\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/06_prepare-the-swift_rename-feed.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/06_prepare-the-swift_rename-feed.png\" alt=\"Rename Feed Class\" title=\"\">\n        </a></p>\n\n<p>Using <code>CTRL</code> + drag, create an <code>IBOutlet</code> from the <code>Feed Table View</code> to <code>FeedViewController</code>. Name the IBOutlet <strong>feedTableView</strong>.\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/07_prepare-the-swift_connect-outlet.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P02-Building-The-Feed-View/assets/07_prepare-the-swift_connect-outlet.png\" alt=\"Connect outlet\" title=\"\">\n        </a></p>\n</div><p>Because the <code>FeedViewController</code> <strong>conforms</strong> to both the <code>UITableViewDataSource</code> and <code>UITableViewDelegate</code> in the <strong>extensions</strong>, we can set the <code>feedTableView</code>'s data source and delegate to be the <code>FeedViewController</code>.</p><div class=\"action\">\n<p>\nSet the <code>delegate</code> and <code>dataSource</code> for the table-view by typing the following code in your <code>viewDidLoad</code> method:</p>\n<pre><span class=\"n\">feedTableView</span><span class=\"p\">.</span><span class=\"n\">dataSource</span> <span class=\"p\">=</span> <span class=\"kc\">self</span>\n<span class=\"n\">feedTableView</span><span class=\"p\">.</span><span class=\"n\">delegate</span> <span class=\"p\">=</span> <span class=\"kc\">self</span>\n</pre>\n</div><p>The table view is fully connected and working. You can run the app to see the one cell created thanks to the lines of code we put in the <code>UITableViewDataSource</code>.</p><p>We're going to be working a lot more with these views later on in the tutorial, but now you've got a sense of <strong>how to display data in tableviews with custom UI!</strong></p>"},{"id":"T0E6OlNlY3Rpb24tMTIwOTc=","title":"Set up Git/GitHub","htmlContent":"<div class=\"action\">\n<p>\nMake your first commit</p>\n<pre>$ git init\n$ git add .\n$ git commit -m <span class=\"s1\">'project init'</span>\n</pre>\n</div><p>Now go to GitHub and create a public repository called <code>Product-Hunt-API</code>, and now associate it as a remote for your local git project and then push to it.</p><div class=\"action\">\n<p>\nPush it!</p>\n<pre>$ git remote add origin GITHUB-REPO-URL\n$ git branch -M main\n$ git push -u origin main\n</pre>\n</div>"}]},"next":{"id":"T0E6OlBhZ2UtMTYyOQ==","slug":"post-model","title":"Creating The Post Model"},"previous":{"id":"T0E6OlBhZ2UtMTYyOQ==","slug":"post-model","title":"Creating The Post Model"}},{"id":"T0E6OlBhZ2UtMTYyOQ==","title":"Creating The Post Model","slug":"post-model","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzE2MQ==","title":"Creating The Post Model","htmlContent":"<p>Let's model the information we will receive for each post. The properties we need are the product's ID, name, tagline, number of votes, and number of comments.</p><div class=\"action\">\n<p>\nCreate a new Swift file and call it <code>Post.swift</code>.</p>\n</div><p>We'll use a <code>struct</code> to define the variables we want to get from the Product Hunt API.</p><div class=\"action\">\n<p>\nCreate a Struct called <code>Post</code>.</p>\n<pre><span class=\"c1\">/// A product retrieved from the Product Hunt API.</span>\n<span class=\"kd\">struct</span> <span class=\"nc\">Post</span> <span class=\"p\">{</span>\n\n<span class=\"p\">}</span>\n</pre>\n<p>Give <code>Post</code> variables that will hold a product's id, name, tagline, number of votes, number of comments, and screenshot url.</p>\n<pre><span class=\"c1\">/// A product retrieved from the Product Hunt API.</span>\n<span class=\"kd\">struct</span> <span class=\"nc\">Post</span> <span class=\"p\">{</span>\n   <span class=\"c1\">// Various properties of a post that we either need or want to display</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">id</span><span class=\"p\">:</span> <span class=\"nb\">Int</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">name</span><span class=\"p\">:</span> <span class=\"nb\">String</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">tagline</span><span class=\"p\">:</span> <span class=\"nb\">String</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">votesCount</span><span class=\"p\">:</span> <span class=\"nb\">Int</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">commentsCount</span><span class=\"p\">:</span> <span class=\"nb\">Int</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>There's more we will need to add to this file to allow it to work effortlessly with network calls. We'll leave it like this for now and move on to create the UI that will show this data.</p>"},{"id":"T0E6OlNlY3Rpb24tNzE2Mg==","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Created Post model'</span>\n$ git push\n</pre>"}]},"next":{"id":"T0E6OlBhZ2UtMTYzMA==","slug":"build-post-cell","title":"Building The Post Cell"},"previous":{"id":"T0E6OlBhZ2UtMTYzMA==","slug":"build-post-cell","title":"Building The Post Cell"}},{"id":"T0E6OlBhZ2UtMTYzMA==","title":"Building The Post Cell","slug":"build-post-cell","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tMTIwOTg=","title":"Building The Post Cell","htmlContent":"<p>The default cell only has room for a string of text. We need it to display more than that.</p><p>We will need 4 labels, for the <em>name</em>, <em>tagline</em>, <em>number of votes</em>, and <em>comments</em>, which will be grouped together in a stack view. We'll also add an image view to display the product's screenshot.</p>"},{"id":"T0E6OlNlY3Rpb24tMTIwOTk=","title":"Updating Storyboard with Custom Cell","htmlContent":"<p>Lets create a new cell in the Storyboard that we can customize.</p><div class=\"action\">\n<p>\nOpen storyboard and open the table view's <code>Attribute Inspector</code> to give it a Dynamic Prototype Cell.\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/01_building-the-post_dynamic-prototype-cell.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/01_building-the-post_dynamic-prototype-cell.png\" alt=\"Prototype Cell\" title=\"\">\n        </a></p>\n</div><p>The Table View Cell is a bit too small at the moment, but we can easily increase the size.</p><div class=\"action\">\n<p>\nClick on the Table View Cell on the storyboard or in the file structure. Increase the size of the Table View Cell to 250 in the <strong>Size Inspector</strong>\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/02_building-the-post_cell-size.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/02_building-the-post_cell-size.png\" alt=\"Increase Cell Size\" title=\"\">\n        </a></p>\n</div><p>We'll use the view that comes with the cell, labeled <code>Content View</code> in Storyboard, as the cell's <strong>background</strong>; so leave that transparent. We'll add a new UIView which will act as a <strong>container</strong> for all the views that will display information about the product.</p>"},{"id":"T0E6OlNlY3Rpb24tMTIxMDA=","title":"Add UIView to Cell","htmlContent":"<div class=\"action\">\n<p>\nDrag a UIView into the prototype cell and pin it on all 4 sides of the <code>Content View</code>. You can make sure it's constaining to the <code>Content View</code> by clicking the down arrow in the Add New Constraints window.\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/00_constraints-to-uiview.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/00_constraints-to-uiview.png\" alt=\"Constraints\" title=\"\">\n        </a></p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tMTIxMDE=","title":"Add Labels & Constraints to Cell","htmlContent":"<p>Now we can add the necessary labels. Let's start with the <strong>name label</strong></p><div class=\"action\">\n<p>\nAdd a UILabel pinned to the top and left of the newly added <code>Container View</code>.</p>\n\n<p>Give the label the text \"Name\" so we can see it better in the Storyboard.</p>\n</div><p>Then the add 2 more labels: one <strong>comments label</strong> named \"Comments: 0\" and one <strong>votes label</strong> named \"Votes: 0\".</p><h2>Implement Constraints</h2><div class=\"action\">\n<p>\nPin a horizontal UIStackView to the top and right of the <code>Container View</code></p>\n\n<p>Place the comments and votes labels inside and make comments the left label and votes the right label.</p>\n\n<p>Give the labels some spacing by selecting the stack view and setting the <strong>Spacing</strong> to 8.</p>\n</div><p>To give the text some room to display information, we can reduce the font size of both labels to 12.</p><div class=\"action\">\n<p>\n Select both labels in the stack view and change their font size to 12 in the <code>Attribute Inspector</code>.</p>\n</div><p>For names that have a longer names, we have to constrain the right side of the name label to not extend longer than the stack view containing the comment and vote counts.</p><div class=\"action\">\n<p>\n Select the name label and create a right horizontal spacing constraint with a spacing of 12 from the <code>Add a Constraint</code> pop over. This will constraint the label to its nearest neighbor which is the horizontal stack view.</p>\n\n<p>Select the name label, go to the <strong>Size Inspector</strong> and scroll down to <strong>Content Hugging Priority</strong> and change the value for <strong>Horizontal</strong> from 251 to 250. This allows the name label to take up the extra horizontal space the comment label and votes label didn't take up.</p>\n</div><p>Next up is the label for the <strong>tagline</strong>.</p><div class=\"action\">\n<p>\nAdd a label pinned to the left, bottom, and right of the <code>Container View</code> and change its Text to say \"Tagline\".</p>\n\n<p>Set the font size of this label to 12.</p>\n</div><p>The last thing we'll add is the UIImageView which will display the product's <strong>screenshot</strong>.</p>"},{"id":"T0E6OlNlY3Rpb24tMTIxMDI=","title":"Add UIImageView to Cell","htmlContent":"<div class=\"action\">\n<p>\nAdd an UIImageView (name it <strong>Preview Image View</strong>) to the center of the cell and pin it to all 4 sides of the <code>Container View</code> with the following constraints:\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/03_building-the-post_pin-image.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/03_building-the-post_pin-image.png\" alt=\"Pin Image View\" title=\"\">\n        </a></p>\n\n<p>You can set the image of the image view to whatever you want. Download free placeholder images <a href=\"https://placeholder.com/\" target=\"_blank\">here</a>. Add <a href=\"http://via.placeholder.com/350x160\" target=\"_blank\">this</a> to your <strong>Assets.xcassets</strong> file in your Xcode project and rename the file to <strong>placeholder.png</strong>. Finally, select placeholder.png as the Image for the UIImageView under the Attribute Inspector.</p>\n\n<p>Lastly, select the image view update the <strong>Content Hugging Priority</strong> value for <strong>Vertical</strong> from 251 to 250. This allows the image view to take up the extra vertical space the Name label and tagline label didn't take up.</p>\n</div><p>To be able to use this custom cell in code it needs to have an <strong>identifier</strong>.</p><div class=\"action\">\n<p>\nSet the <code>Identifier</code> of the cell to <code>postCell</code> in the cell's <code>Identity Inspector</code>.</p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tMTIxMDM=","title":"Product So Far","htmlContent":"<p>Now we have all the UI built out to display the information we'll be getting from the API. We're getting more comfortable with <strong>displaying data in tableviews with custom UI</strong> as well as beginning to learn <strong>how to take advantage of mock data</strong> through using the <code>placeholder</code> image. We'll keep working on each of those as we continue.</p><p>Check out the completed custom cell below. Note that your constraints may not exactly match what is shown below. The important thing is that the layout matches, and that you followed the constraints properly as described in this section.</p><div class=\"solution\">\n<p>\nClick on the image if you want to see all the information on the Project Navigator:\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/04_building-the-post_custom-cell.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P04-Building-The-Post-Cell/assets/04_building-the-post_custom-cell.png\" alt=\"Completed custom cell\" title=\"\">\n        </a></p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tMTIxMDQ=","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Completed Post Cell view'</span>\n$ git push\n</pre>"}]},"next":{"id":"T0E6OlBhZ2UtMTYzMQ==","slug":"create-post-cell-class","title":"Creating the Post Cell Class"},"previous":{"id":"T0E6OlBhZ2UtMTYzMQ==","slug":"create-post-cell-class","title":"Creating the Post Cell Class"}},{"id":"T0E6OlBhZ2UtMTYzMQ==","title":"Creating the Post Cell Class","slug":"create-post-cell-class","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzE2NQ==","title":"Creating the Post Cell Class","htmlContent":"<p>In order to access the custom cell's views in code, a custom class is needed.</p><p>We'll call this custom class <code>PostTableViewCell</code> and place all the methods related to keeping the cell up-to-date in here.</p><p>Start by creating the file.</p><div class=\"action\">\n<p>\nCreate a new file using the <code>Cocoa Touch Class</code> template.</p>\n\n<p>Name the Class <code>PostTableViewCell</code> and make it a Subclass of <code>UITableViewCell</code> from the dropdown menu.</p>\n\n<p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P05-Creating-The-Post-Cell-Class/assets/01_creating-the-post_view-cell.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P05-Creating-The-Post-Cell-Class/assets/01_creating-the-post_view-cell.png\" alt=\"Create post cell\" title=\"\">\n        </a></p>\n</div><p>In the new file we just created, we won't be needing the <code>awakeFromNib()</code> and <code>setSelected(:, animated:)</code> methods. So, you can delete those (or keep them, there's no harm done).</p><p>Next we'll set the Prototype Cell we created in Storyboard to use this class.</p><div class=\"action\">\n<p>\nGo to Storyboard and select the cell we created in the previous chapter (be sure to select the <code>UITableViewCell</code> and not the <code>contentView</code> or the <code>Container View</code> we created).</p>\n\n<p>In the <code>Identity Inspector</code>, change the <code>Class</code> field to <code>PostTableViewCell</code>.</p>\n</div><p>Now we can connect the <code>IBOutlets</code> to the class we created.</p><div class=\"action\">\n<p>\nCreate weak <code>IBOutlets</code> for the labels and image view inside <code>PostTableViewCell.swift</code>\nName them <code>nameLabel</code>, <code>taglineLabel</code>, <code>commentsCountLabel</code>, <code>votesCountLabel</code>, and <code>previewImageView</code></p>\n</div><p>To make updating these views quick and easy, we'll use a <strong>property observer</strong> on a <code>Post</code> object.</p><div class=\"info\">\n<p>\nProperty observers watch and respond to changes in a property's value and are called every time a new value is set.</p>\n</div><!-- --><div class=\"action\">\n<p>\nBelow your <code>IBOutlets</code> create a new optional <code>Post</code> var called <code>post</code></p>\n\n<p>Now add the property observer <code>didSet</code></p>\n<pre><span class=\"p\">...</span>\n\n<span class=\"kd\">var</span> <span class=\"nv\">post</span><span class=\"p\">:</span> <span class=\"n\">Post</span><span class=\"p\">?</span> <span class=\"p\">{</span>\n   <span class=\"kr\">didSet</span> <span class=\"p\">{</span>\n\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Any code we place inside <code>didSet {}</code> will execute every time the <code>post</code> variable is set. This is a good place to update the labels and image view.</p><div class=\"action\">\n<p>\nAdd the following lines to update the views inside the property observer:</p>\n<pre><span class=\"c1\">// Runs every time the post variable is set</span>\n<span class=\"kr\">didSet</span> <span class=\"p\">{</span>\n   <span class=\"c1\">// make sure we return if post doesn't exist</span>\n   <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">post</span> <span class=\"p\">=</span> <span class=\"n\">post</span> <span class=\"k\">else</span> <span class=\"p\">{</span> <span class=\"k\">return</span> <span class=\"p\">}</span>\n   <span class=\"c1\">// Assign our UI elements to their post counterparts</span>\n   <span class=\"n\">nameLabel</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">name</span>\n   <span class=\"n\">taglineLabel</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">tagline</span>\n   <span class=\"n\">commentsCountLabel</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"s\">\"Comments: </span><span class=\"si\">\\(</span><span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">commentsCount</span><span class=\"si\">)</span><span class=\"s\">\"</span>\n   <span class=\"n\">votesCountLabel</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"s\">\"Votes: </span><span class=\"si\">\\(</span><span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">votesCount</span><span class=\"si\">)</span><span class=\"s\">\"</span>\n   <span class=\"c1\">// We'll write this next!</span>\n   <span class=\"n\">updatePreviewImage</span><span class=\"p\">()</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE2Ng==","title":"Placeholder Images","htmlContent":"<p>Next create the <code>updatePreviewImage()</code> method. For now it will be very simple and give every post a placeholder image.</p><div class=\"action\">\n<p></p>\n<pre><span class=\"p\">...</span>\n\n<span class=\"kd\">func</span> <span class=\"nf\">updatePreviewImage</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n   <span class=\"c1\">// make sure we return if post doesn't exist</span>\n   <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">post</span> <span class=\"p\">=</span> <span class=\"n\">post</span> <span class=\"k\">else</span> <span class=\"p\">{</span> <span class=\"k\">return</span> <span class=\"p\">}</span>\n   <span class=\"c1\">// assign the placeholder image to the UI element</span>\n   <span class=\"n\">previewImageView</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"p\">=</span> <span class=\"bp\">UIImage</span><span class=\"p\">(</span><span class=\"n\">named</span><span class=\"p\">:</span> <span class=\"s\">\"placeholder\"</span><span class=\"p\">)</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Now the custom cell is ready to be used by a UITableView. Make sure your variable names match up with your Storyboard!</p><div class=\"solution\">\n<p></p>\n<pre><span class=\"kd\">class</span> <span class=\"nc\">PostTableViewCell</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// All of our UI elements we'll use for our view that relate to properties of a post</span>\n  <span class=\"kr\">@IBOutlet</span> <span class=\"kr\">weak</span> <span class=\"kd\">var</span> <span class=\"nv\">nameLabel</span><span class=\"p\">:</span> <span class=\"bp\">UILabel</span><span class=\"p\">!</span>\n  <span class=\"kr\">@IBOutlet</span> <span class=\"kr\">weak</span> <span class=\"kd\">var</span> <span class=\"nv\">taglineLabel</span><span class=\"p\">:</span> <span class=\"bp\">UILabel</span><span class=\"p\">!</span>\n  <span class=\"kr\">@IBOutlet</span> <span class=\"kr\">weak</span> <span class=\"kd\">var</span> <span class=\"nv\">commentsCountLabel</span><span class=\"p\">:</span> <span class=\"bp\">UILabel</span><span class=\"p\">!</span>\n  <span class=\"kr\">@IBOutlet</span> <span class=\"kr\">weak</span> <span class=\"kd\">var</span> <span class=\"nv\">votesCountLabel</span><span class=\"p\">:</span> <span class=\"bp\">UILabel</span><span class=\"p\">!</span>\n  <span class=\"kr\">@IBOutlet</span> <span class=\"kr\">weak</span> <span class=\"kd\">var</span> <span class=\"nv\">previewImageView</span><span class=\"p\">:</span> <span class=\"bp\">UIImageView</span><span class=\"p\">!</span>\n\n  <span class=\"kd\">var</span> <span class=\"nv\">post</span><span class=\"p\">:</span> <span class=\"n\">Post</span><span class=\"p\">?</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// Runs every time the post variable is set</span>\n    <span class=\"kr\">didSet</span> <span class=\"p\">{</span>\n       <span class=\"c1\">// make sure we return if post doesn't exist</span>\n       <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">post</span> <span class=\"p\">=</span> <span class=\"n\">post</span> <span class=\"k\">else</span> <span class=\"p\">{</span> <span class=\"k\">return</span> <span class=\"p\">}</span>\n       <span class=\"c1\">// Assign our UI elements to their post counterparts</span>\n       <span class=\"n\">nameLabel</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">name</span>\n       <span class=\"n\">taglineLabel</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">tagline</span>\n       <span class=\"n\">commentsCountLabel</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"s\">\"Comments: </span><span class=\"si\">\\(</span><span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">commentsCount</span><span class=\"si\">)</span><span class=\"s\">\"</span>\n       <span class=\"n\">votesCountLabel</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"s\">\"Votes: </span><span class=\"si\">\\(</span><span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">votesCount</span><span class=\"si\">)</span><span class=\"s\">\"</span>\n       <span class=\"c1\">// We'll write this next!</span>\n       <span class=\"n\">updatePreviewImage</span><span class=\"p\">()</span>\n    <span class=\"p\">}</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"kd\">func</span> <span class=\"nf\">updatePreviewImage</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n     <span class=\"c1\">// make sure we return if post doesn't exist</span>\n     <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">post</span> <span class=\"p\">=</span> <span class=\"n\">post</span> <span class=\"k\">else</span> <span class=\"p\">{</span> <span class=\"k\">return</span> <span class=\"p\">}</span>\n     <span class=\"c1\">// assign the placeholder image to the UI element</span>\n     <span class=\"n\">previewImageView</span><span class=\"p\">.</span><span class=\"n\">image</span> <span class=\"p\">=</span> <span class=\"bp\">UIImage</span><span class=\"p\">(</span><span class=\"n\">named</span><span class=\"p\">:</span> <span class=\"s\">\"placeholder\"</span><span class=\"p\">)</span>\n  <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE2Nw==","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Created custom class for Posts'</span>\n$ git push\n</pre>"}]},"next":{"id":"T0E6OlBhZ2UtMTYzMg==","slug":"test-feed-view","title":"Testing Feed Table View"},"previous":{"id":"T0E6OlBhZ2UtMTYzMg==","slug":"test-feed-view","title":"Testing Feed Table View"}},{"id":"T0E6OlBhZ2UtMTYzMg==","title":"Testing Feed Table View","slug":"test-feed-view","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzg4Mw==","title":"Testing Feed Table View","htmlContent":"<p>With our custom cell setup, we now have all the UI elements we need to see the <code>Feed View</code> in action. However, we won't be making any network requests just yet; instead we'll use <strong>mock data</strong> to emulate the data that we will receive from an API request.</p>"},{"id":"T0E6OlNlY3Rpb24tNzg4NA==","title":"Test UI Without Data","htmlContent":"<p>First let's test things without using any real data from Product Hunt's API.</p><div class=\"action\">\n<p>\nOpen <code>FeedViewController.swift</code> and go to the <code>UITableViewDataSource</code> extension to update the body of the <strong>second</strong> <code>tableView</code> method using the code below (check the parameters so that you're sure you're updating the right method):</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">cellForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n   <span class=\"c1\">// dequeue and return an available cell, instead of creating a new cell</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">cell</span> <span class=\"p\">=</span> <span class=\"n\">tableView</span><span class=\"p\">.</span><span class=\"n\">dequeueReusableCell</span><span class=\"p\">(</span><span class=\"n\">withIdentifier</span><span class=\"p\">:</span> <span class=\"s\">\"postCell\"</span><span class=\"p\">,</span> <span class=\"k\">for</span><span class=\"p\">:</span> <span class=\"n\">indexPath</span><span class=\"p\">)</span> <span class=\"k\">as</span><span class=\"p\">!</span> <span class=\"n\">PostTableViewCell</span>\n\n   <span class=\"k\">return</span> <span class=\"n\">cell</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>We dequeue a cell using the <code>postCell</code> identifier we provided in Storyboard earlier and simply return it.</p><div class=\"info\">\n<p>\nThe first line in the above function uses the method <code>dequeueReusableCell(withIdentifier:)</code></p>\n\n<p>This is used for performance reasons as it <strong>dequeues</strong> any available cells and returns it as the table-view cell associated with the identifier provided, skipping a lot of the overhead needed to create an entirely new cell.</p>\n</div><p>We also need to update the size of the cell in our <code>FeedViewController</code>.</p><div class=\"action\">\n<p>\nGo to the <code>UITableViewDelegate</code> extension and add the following method</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">heightForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"n\">CGFloat</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// provide a fixed size</span>\n  <span class=\"k\">return</span> <span class=\"mi\">250</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Run the app to see how it looks &#128076;</p><p>You should see something awesome like this:\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P06-Testing-Feed-Table-View/assets/01_test-ui-without_feed-without-data.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P06-Testing-Feed-Table-View/assets/01_test-ui-without_feed-without-data.png\" alt=\"Feed without data\" title=\"\">\n        </a></p>"},{"id":"T0E6OlNlY3Rpb24tNzg4NQ==","title":"Use Mock Data To Display Information","htmlContent":"<p>Using Mock Data allows us to easily test our app without having to create an entire networking layer. We'll simply create an array with <code>Post</code> objects and provide the data for each post ourselves.</p><div class=\"action\">\n<p>\nCreate an array of Posts in <code>FeedViewController</code>, below your <code>IBOutlet feedTableView</code> using a closure.</p>\n<pre><span class=\"p\">...</span>\n\n<span class=\"c1\">// Array of Post objects to simulate real data coming in</span>\n<span class=\"c1\">// Make sure each property that we're assigning to a UI element has a value for each mock Post.</span>\n<span class=\"kd\">var</span> <span class=\"nv\">mockData</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"n\">Post</span><span class=\"p\">]</span> <span class=\"p\">=</span> <span class=\"p\">{</span>\n   <span class=\"kd\">var</span> <span class=\"nv\">meTube</span> <span class=\"p\">=</span> <span class=\"n\">Post</span><span class=\"p\">(</span><span class=\"n\">id</span><span class=\"p\">:</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">:</span> <span class=\"s\">\"MeTube\"</span><span class=\"p\">,</span> <span class=\"n\">tagline</span><span class=\"p\">:</span> <span class=\"s\">\"Stream videos for free!\"</span><span class=\"p\">,</span> <span class=\"n\">votesCount</span><span class=\"p\">:</span> <span class=\"mi\">25</span><span class=\"p\">,</span> <span class=\"n\">commentsCount</span><span class=\"p\">:</span> <span class=\"mi\">4</span><span class=\"p\">)</span>\n   <span class=\"kd\">var</span> <span class=\"nv\">boogle</span> <span class=\"p\">=</span> <span class=\"n\">Post</span><span class=\"p\">(</span><span class=\"n\">id</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">:</span> <span class=\"s\">\"Boogle\"</span><span class=\"p\">,</span> <span class=\"n\">tagline</span><span class=\"p\">:</span> <span class=\"s\">\"Search anything!\"</span><span class=\"p\">,</span> <span class=\"n\">votesCount</span><span class=\"p\">:</span> <span class=\"mi\">1000</span><span class=\"p\">,</span> <span class=\"n\">commentsCount</span><span class=\"p\">:</span> <span class=\"mi\">50</span><span class=\"p\">)</span>\n   <span class=\"kd\">var</span> <span class=\"nv\">meTunes</span> <span class=\"p\">=</span> <span class=\"n\">Post</span><span class=\"p\">(</span><span class=\"n\">id</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">:</span> <span class=\"s\">\"meTunes\"</span><span class=\"p\">,</span> <span class=\"n\">tagline</span><span class=\"p\">:</span> <span class=\"s\">\"Listen to any song!\"</span><span class=\"p\">,</span> <span class=\"n\">votesCount</span><span class=\"p\">:</span> <span class=\"mi\">25000</span><span class=\"p\">,</span> <span class=\"n\">commentsCount</span><span class=\"p\">:</span> <span class=\"mi\">590</span><span class=\"p\">)</span>\n\n   <span class=\"k\">return</span> <span class=\"p\">[</span><span class=\"n\">meTube</span><span class=\"p\">,</span> <span class=\"n\">boogle</span><span class=\"p\">,</span> <span class=\"n\">meTunes</span><span class=\"p\">]</span>\n<span class=\"p\">}()</span>\n</pre>\n</div><p>The data is essentially fake, so you can create whatever product you want!</p><p>We can now use this array as a <strong>datasource</strong> for the table view, allowing us to provide data for the labels in the custom cell we created.</p><div class=\"action\">\n<p>\nUpdate the following methods in the <code>UITableViewDataSource</code> extension:</p>\n<pre><span class=\"c1\">// Determines how many cells will be shown on the table view.</span>\n<span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">numberOfRowsInSection</span> <span class=\"n\">section</span><span class=\"p\">:</span> <span class=\"nb\">Int</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Int</span> <span class=\"p\">{</span>\n  <span class=\"k\">return</span> <span class=\"n\">mockData</span><span class=\"p\">.</span><span class=\"bp\">count</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// Creates and configures each cell.</span>\n<span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">cellForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// Grab an available cell</span>\n  <span class=\"kd\">let</span> <span class=\"nv\">cell</span> <span class=\"p\">=</span> <span class=\"n\">tableView</span><span class=\"p\">.</span><span class=\"n\">dequeueReusableCell</span><span class=\"p\">(</span><span class=\"n\">withIdentifier</span><span class=\"p\">:</span> <span class=\"s\">\"postCell\"</span><span class=\"p\">,</span> <span class=\"k\">for</span><span class=\"p\">:</span> <span class=\"n\">indexPath</span><span class=\"p\">)</span> <span class=\"k\">as</span><span class=\"p\">!</span> <span class=\"n\">PostTableViewCell</span>\n\n  <span class=\"c1\">// Grab a post from our \"data\"</span>\n  <span class=\"kd\">let</span> <span class=\"nv\">post</span> <span class=\"p\">=</span> <span class=\"n\">mockData</span><span class=\"p\">[</span><span class=\"n\">indexPath</span><span class=\"p\">.</span><span class=\"n\">row</span><span class=\"p\">]</span>\n  <span class=\"c1\">// Assign a post to that cell</span>\n  <span class=\"n\">cell</span><span class=\"p\">.</span><span class=\"n\">post</span> <span class=\"p\">=</span> <span class=\"n\">post</span>\n\n  <span class=\"k\">return</span> <span class=\"n\">cell</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Because we used a property observer to update the labels, we only need to set the cell's <code>post</code> property to give it the data it needs.</p>"},{"id":"T0E6OlNlY3Rpb24tNzg4Ng==","title":"Product So Far","htmlContent":"<p>Run the app again to see how it looks. You should see the cell's filled with the information provided by our mock data:\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P06-Testing-Feed-Table-View/assets/02_use-mock-data_feed-with-data.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P06-Testing-Feed-Table-View/assets/02_use-mock-data_feed-with-data.png\" alt=\"Feed with data\" title=\"\">\n        </a></p><p>We've successfully integrated <strong>the use of mock data</strong> into our app! We are now ready to get into networking! But first we need to update our model.</p>"},{"id":"T0E6OlNlY3Rpb24tNzg4Nw==","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Tests with mock data'</span>\n$ git push\n</pre>"}]},"next":{"id":"T0E6OlBhZ2UtMTYzMw==","slug":"update-post-model","title":"Updating Post Model"},"previous":{"id":"T0E6OlBhZ2UtMTYzMw==","slug":"update-post-model","title":"Updating Post Model"}},{"id":"T0E6OlBhZ2UtMTYzMw==","title":"Updating Post Model","slug":"update-post-model","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzE3Mg==","title":"Updating Post Model","htmlContent":"<p>In order for this model to work well with network requests, we will make it <strong>decodable</strong>. Making our model <a href=\"https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types\" target=\"_blank\">decodable</a> means that we can take information from external resources (such as the Product Hunt API) and transform it into something that works with our models, like our <code>Post</code> model!</p>"},{"id":"T0E6OlNlY3Rpb24tNzE3Mw==","title":"Getting Started","htmlContent":"<p>First, let's add a variable for the preview image url:</p><div class=\"action\">\n<p>\nAdd previewImageUrl variable at the bottom of <code>Post</code> model located in the <code>Post.swift</code> file.</p>\n<pre> <span class=\"p\">...</span>\n <span class=\"kd\">let</span> <span class=\"nv\">previewImageURL</span><span class=\"p\">:</span> <span class=\"n\">URL</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>This will hold the link to the screenshot of the product and will allow us to download the image later on.</p><p>Next, let's make <code>Post</code> <strong>decodable</strong> by conforming to the <code>Decodable</code> protocol.</p><div class=\"action\">\n<p>\nCreate an <code>extension</code> at the bottom of your <code>Post</code> model that makes it <code>decodable</code>. We're extending it for ease of readability since we're going to be adding more code later.</p>\n<pre><span class=\"kd\">struct</span> <span class=\"nc\">Post</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// current code</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// </span><span class=\"cs\">MARK:</span><span class=\"c1\"> Decodable</span>\n<span class=\"kd\">extension</span> <span class=\"nc\">Post</span><span class=\"p\">:</span> <span class=\"n\">Decodable</span> <span class=\"p\">{</span>\n\n<span class=\"p\">}</span>\n</pre>\n</div><!-- --><div class=\"info\">\n<p></p>\n\n<p>This tutorial describes <code>Decodable</code> at a high level. If you want to dive deeper into the inner workings of what's going on, Greg Heo's <a href=\"https://swiftunboxed.com/stdlib/json-decoder-decodable/\" target=\"_blank\">JSON to Swift with Decoder and Decodable</a> article does a fantastic job of explaining the inner workings!</p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE3NA==","title":"Add Coding Keys","htmlContent":"<p>We'll need to define <strong>coding keys</strong> to tell Swift exactly where to find the information to fill the model's variables. However, we actually only need this because the Product Hunt API uses a different naming convention for it's properties.</p><div class=\"action\">\n<p>\nCreate an <code>enum</code> called <code>PostKeys</code> with the raw type as <code>String</code> and conforms to <code>CodingKey</code> and place it inside the <code>Post: Decodable</code> extension.</p>\n<pre><span class=\"kd\">extension</span> <span class=\"nc\">Post</span><span class=\"p\">:</span> <span class=\"n\">Decodable</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// properties within a Post returned from the Product Hunt API that we want to extract the info from.</span>\n    <span class=\"kd\">enum</span> <span class=\"nc\">PostKeys</span><span class=\"p\">:</span> <span class=\"nb\">String</span><span class=\"p\">,</span> <span class=\"n\">CodingKey</span> <span class=\"p\">{</span>\n        <span class=\"c1\">// first three match our variable names for our Post struct</span>\n        <span class=\"k\">case</span> <span class=\"n\">id</span>\n        <span class=\"k\">case</span> <span class=\"n\">name</span>\n        <span class=\"k\">case</span> <span class=\"n\">tagline</span>\n        <span class=\"c1\">// these three need to be mapped since they're named differently on the API compared to our struct</span>\n        <span class=\"k\">case</span> <span class=\"n\">votesCount</span> <span class=\"p\">=</span> <span class=\"s\">\"votes_count\"</span>\n        <span class=\"k\">case</span> <span class=\"n\">commentsCount</span> <span class=\"p\">=</span> <span class=\"s\">\"comments_count\"</span>\n        <span class=\"k\">case</span> <span class=\"n\">previewImageURL</span> <span class=\"p\">=</span> <span class=\"s\">\"screenshot_url\"</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n<p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P07-Updating-Post-Model/assets/01_add-coding-keys_post-coding-keys.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P07-Updating-Post-Model/assets/01_add-coding-keys_post-coding-keys.png\" alt=\"Post Keys\" title=\"\">\n        </a></p>\n</div><p>Note how <code>votesCount</code>, <code>commentsCount</code>, and <code>previewImageUrl</code> are the only variables that are set to a string. This is because in the JSON we receive from the request, these variables are named differently (using <strong>snake_case</strong>, rather than <strong>camelCase</strong> which is the recommended practice for Swift).</p><p>In fact, if we did not plan to collect these variables from the JSON, we would not need to create any <strong>coding keys</strong>.</p><p>Also, there are cases where you simply want to rename the property differently, such as for the <code>previewImageUrl</code>. We'll create a coding key for that as well and put it in our <code>Post: Decodable</code> extension:</p><div class=\"action\">\n<p>\nAdd a CodingKey for the preview image in the same file.</p>\n<pre><span class=\"kd\">enum</span> <span class=\"nc\">PreviewImageURLKeys</span><span class=\"p\">:</span> <span class=\"nb\">String</span><span class=\"p\">,</span> <span class=\"n\">CodingKey</span> <span class=\"p\">{</span>\n   <span class=\"c1\">// for all posts, we only want the 850px image</span>\n   <span class=\"c1\">// Check out the screenshot_url property in our Postman call to see where this livesx</span>\n   <span class=\"k\">case</span> <span class=\"n\">imageURL</span> <span class=\"p\">=</span> <span class=\"s\">\"850px\"</span>\n<span class=\"p\">}</span>\n</pre>\n<p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P07-Updating-Post-Model/assets/02_add-coding-keys_preview-coding-keys.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P07-Updating-Post-Model/assets/02_add-coding-keys_preview-coding-keys.png\" alt=\"Preview Keys\" title=\"\">\n        </a></p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE3NQ==","title":"Initializing A Decodable","htmlContent":"<p>Now that we have all our necessary coding keys, the next step will be to setup the initializer for our model.</p><div class=\"action\">\n<p>\nAdd this initializer inside the <code>Post: Decodable</code> extension, below the <code>enums</code> you made earlier:</p>\n<pre><span class=\"kd\">init</span><span class=\"p\">(</span><span class=\"n\">from</span> <span class=\"n\">decoder</span><span class=\"p\">:</span> <span class=\"n\">Decoder</span><span class=\"p\">)</span> <span class=\"kr\">throws</span> <span class=\"p\">{</span>\n\n<span class=\"p\">}</span>\n</pre>\n</div><p>We'll first need to <em>extract the properties</em> from the <code>post</code> object that we get back from the Product Hunt API. This is done using <strong>containers</strong> which uses <code>CodingKeys</code>:</p><div class=\"info\">\n<p>\n<a href=\"https://developer.apple.com/documentation/swift/decoder/2892621-container\" target=\"_blank\">Containers</a> allow the <code>decoders</code> to return their data based off of the provided <code>CodingKeys</code></p>\n</div><!-- --><div class=\"action\">\n<p>\nAdd this to the body of the <code>init</code> you just created:</p>\n<pre><span class=\"c1\">// Decode the Post from the API call</span>\n<span class=\"kd\">let</span> <span class=\"nv\">postsContainer</span> <span class=\"p\">=</span> <span class=\"k\">try</span> <span class=\"n\">decoder</span><span class=\"p\">.</span><span class=\"n\">container</span><span class=\"p\">(</span><span class=\"n\">keyedBy</span><span class=\"p\">:</span> <span class=\"n\">PostKeys</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">)</span>\n</pre>\n</div><p>Now that we have stored the <code>post</code> object in a container, we can go in and grab all the information we need from it!</p><div class=\"action\">\n<p>\nBelow the <code>postsContainer</code> line, set the variables of the <code>Post</code> using the <code>postContainer</code> you just created.</p>\n<pre>  <span class=\"p\">...</span>\n  <span class=\"c1\">// Decode each of the properties from the API into the appropriate type (string, etc.) for their associated struct variable</span>\n  <span class=\"n\">id</span> <span class=\"p\">=</span> <span class=\"k\">try</span> <span class=\"n\">postsContainer</span><span class=\"p\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"nb\">Int</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">forKey</span><span class=\"p\">:</span> <span class=\"p\">.</span><span class=\"n\">id</span><span class=\"p\">)</span>\n  <span class=\"n\">name</span> <span class=\"p\">=</span> <span class=\"k\">try</span> <span class=\"n\">postsContainer</span><span class=\"p\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"nb\">String</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">forKey</span><span class=\"p\">:</span> <span class=\"p\">.</span><span class=\"n\">name</span><span class=\"p\">)</span>\n  <span class=\"n\">tagline</span> <span class=\"p\">=</span> <span class=\"k\">try</span> <span class=\"n\">postsContainer</span><span class=\"p\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"nb\">String</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">forKey</span><span class=\"p\">:</span> <span class=\"p\">.</span><span class=\"n\">tagline</span><span class=\"p\">)</span>\n  <span class=\"n\">votesCount</span> <span class=\"p\">=</span> <span class=\"k\">try</span> <span class=\"n\">postsContainer</span><span class=\"p\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"nb\">Int</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">forKey</span><span class=\"p\">:</span> <span class=\"p\">.</span><span class=\"n\">votesCount</span><span class=\"p\">)</span>\n  <span class=\"n\">commentsCount</span> <span class=\"p\">=</span> <span class=\"k\">try</span> <span class=\"n\">postsContainer</span><span class=\"p\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"nb\">Int</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">forKey</span><span class=\"p\">:</span> <span class=\"p\">.</span><span class=\"n\">commentsCount</span><span class=\"p\">)</span>\n<span class=\"p\">}</span>\n</pre>\n<p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P07-Updating-Post-Model/assets/03_initializing-a_post-container.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P07-Updating-Post-Model/assets/03_initializing-a_post-container.png\" alt=\"Posts container\" title=\"\">\n        </a></p>\n</div><p>Finally, we need to set the <code>previewImageURL</code>. The actual URL that we need from <code>screenshot_url</code> is nested within the <code>screenshot_url</code> object in the API response, so we'll need to access it through a <strong>nested container</strong> (more info on those <a href=\"https://developer.apple.com/documentation/swift/keyeddecodingcontainer/2893204-nestedcontainer\" target=\"_blank\">here</a>) using the <code>PreviewImageURLKeys</code>:</p><div class=\"action\">\n<p>\nAdd this add the bottom of the initializer:</p>\n<pre>   <span class=\"p\">...</span>\n\n   <span class=\"c1\">// First we need to get a container (screenshot_url/previewImageURL) nested within our postsContainer.</span>\n   <span class=\"c1\">// If it only had a single value like the other properties, we wouldn't need to use nestedContainer</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">screenshotURLContainer</span> <span class=\"p\">=</span> <span class=\"k\">try</span> <span class=\"n\">postsContainer</span><span class=\"p\">.</span><span class=\"n\">nestedContainer</span><span class=\"p\">(</span><span class=\"n\">keyedBy</span><span class=\"p\">:</span> <span class=\"n\">PreviewImageURLKeys</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">forKey</span><span class=\"p\">:</span> <span class=\"p\">.</span><span class=\"n\">previewImageURL</span><span class=\"p\">)</span>\n   <span class=\"c1\">// Decode the image and assign it to the variable</span>\n   <span class=\"n\">previewImageURL</span> <span class=\"p\">=</span> <span class=\"k\">try</span> <span class=\"n\">screenshotURLContainer</span><span class=\"p\">.</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"n\">URL</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">forKey</span><span class=\"p\">:</span> <span class=\"p\">.</span><span class=\"n\">imageURL</span><span class=\"p\">)</span>\n<span class=\"p\">}</span>\n</pre>\n<p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P07-Updating-Post-Model/assets/04_initializing-a_screenshot-container.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P07-Updating-Post-Model/assets/04_initializing-a_screenshot-container.png\" alt=\"Screenshot container\" title=\"\">\n        </a></p>\n</div><p>Now the model is ready to go! But there's one more thing we need to add to make things easier.</p><p>The products we retrieve from the API are inside the array called \"posts\". We can model this using a Struct:</p><div class=\"action\">\n<p>\nAdd this below your <code>Post</code> Struct, and above your <code>extension Post: Decodable</code>:</p>\n<pre><span class=\"kd\">struct</span> <span class=\"nc\">Post</span> <span class=\"p\">{</span>\n<span class=\"p\">...</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// Have a matching decodable array in our struct for the array of posts we get back from the API</span>\n<span class=\"kd\">struct</span> <span class=\"nc\">PostList</span><span class=\"p\">:</span> <span class=\"n\">Decodable</span> <span class=\"p\">{</span>\n   <span class=\"kd\">var</span> <span class=\"nv\">posts</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"n\">Post</span><span class=\"p\">]</span>\n<span class=\"p\">}</span>\n\n<span class=\"kd\">extension</span> <span class=\"nc\">Post</span><span class=\"p\">:</span> <span class=\"n\">Decodable</span> <span class=\"p\">{</span>\n<span class=\"p\">...</span>\n<span class=\"p\">}</span>\n</pre>\n</div><!-- --><div class=\"info\">\n<p></p>\n\n<p>What if we want to decode a nested JSON file? See answer in <em>Code Different's</em>  <a href=\"https://stackoverflow.com/questions/44549310/how-to-decode-a-nested-json-struct-with-swift-decodable-protocol\" target=\"_blank\">Stack Overflow</a></p>\n</div><p>We just went through a lot of important stuff! We learned <strong>how to decode JSON into our Swift models</strong>, and also learned a bit more on <strong>how to work with APIs</strong> in order to get data flowing into our app!</p><p>We can't get our data flowing just yet though, since we have don't have a way to interface with the Product Hunt API. To do so, we'll need a networking layer, so let's get to it!</p>"},{"id":"T0E6OlNlY3Rpb24tNzE3Ng==","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Decodable model'</span>\n$ git push\n</pre>"}]},"next":{"id":"T0E6OlBhZ2UtMTYzNA==","slug":"create-networking-layer","title":"Creating The Networking Layer"},"previous":{"id":"T0E6OlBhZ2UtMTYzNA==","slug":"create-networking-layer","title":"Creating The Networking Layer"}},{"id":"T0E6OlBhZ2UtMTYzNA==","title":"Creating The Networking Layer","slug":"create-networking-layer","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tMTIxMDU=","title":"Creating The Networking Layer","htmlContent":"<p>With our model prepared, the networking layer will be pretty simple to create.</p>"},{"id":"T0E6OlNlY3Rpb24tMTIxMDY=","title":"Introduction to Network Managers","htmlContent":"<p>In this section, we'll be creating the network layer of the app. You may be wondering what a network manager is or even what networking in general is. Lets take a closer look before diving into code.</p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P08-Creating-The-Networking-Layer/assets/00_networking.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P08-Creating-The-Networking-Layer/assets/00_networking.png\" alt=\"Networking Diagram\" title=\"\">\n        </a></p><p>Networking (aka computer networking) is how information and data get transported and exchanged between various information systems.</p><p>Looking at the diagram, the client (in our case, the iphone or simulator) makes a request of some sort (typially some sort of information like text, images, videos, etc) to a server, the server then takes in the request and handles its response before sending the information to the client.</p><p>Here are a few note-worthy key-terms to help you understand the parts of the networking proccess better:</p><p><strong>Client</strong>: a computer in a network that uses the services provided by a server.</p><p><strong>Server</strong>: a piece of computer hardware or software (computer program) that provides functionality for other programs or devices (ie clients)</p><p><strong>API</strong>: part of the server that receives requests and sends responses.</p><p><strong>Network Manager / Networking Layer</strong>: a well-structured chunk of code used to make API requests and handle its responses from an external server.</p><p>What we'll be doing moving forward in this section is creating a custon networking layer that communicates with the Product Hunt API. In doing so, this is how we will be populating data in our storyboard instead of having mock data.</p><p>The information you take away from this section will be especially helpful the further you grow in tech as majority of apps eventually communicate with the internet in some way and <strong>this</strong> is where it all starts.</p>"},{"id":"T0E6OlNlY3Rpb24tMTIxMDc=","title":"Create Manager Class","htmlContent":"<p>Now that you're a master of the fundamentals of networking, let's get started!</p><div class=\"action\">\n<p>\nStart by creating a new <code>Swift</code> file named <code>NetworkManager.swift</code></p>\n</div><p>We'll keep everything in a class called <code>NetworkManager</code></p><div class=\"action\">\n<p>\nCreate a <code>NetworkManager</code> class with the following variables. Remember to replace the value of <code>token</code> with your Product Hunt API token!</p>\n<pre><span class=\"kd\">class</span> <span class=\"nc\">NetworkManager</span> <span class=\"p\">{</span>\n    <span class=\"c1\">// shared singleton session object used to run tasks. Will be useful later</span>\n    <span class=\"kd\">let</span> <span class=\"nv\">urlSession</span> <span class=\"p\">=</span> <span class=\"n\">URLSession</span><span class=\"p\">.</span><span class=\"n\">shared</span>\n\n    <span class=\"kd\">var</span> <span class=\"nv\">baseURL</span> <span class=\"p\">=</span> <span class=\"s\">\"https://api.producthunt.com/v1/\"</span>\n    <span class=\"kd\">var</span> <span class=\"nv\">token</span> <span class=\"p\">=</span> <span class=\"s\">\"replace-me-with-your-token-from-product-hunt-api-dashboard-&#128591;\"</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>This is what we'll use to create the network request.</p>"},{"id":"T0E6OlNlY3Rpb24tMTIxMDg=","title":"Get Posts Method","htmlContent":"<p>Next we'll create the method that handles the request.</p><div class=\"action\">\n<p>\nCreate a <code>getPosts()</code> method in your new <code>NetworkManager</code> class</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">getPosts</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n\n<span class=\"p\">}</span>\n</pre>\n</div><p>Because network requests require continuous data flow, this can result in different speeds depending on the network. To account for this, we'll use an <strong>escaping closure</strong> as a completion handler in order to return data.</p><p>Using the normal function <code>return</code> would result in inconsistent results, as the data retrieved from a request might not always be prepared before the method returns. We need to adjust the parameter list for our <code>getPosts</code> method.</p><div class=\"action\">\n<p>\nAdd an <strong>escaping closure</strong> to <code>getPosts()</code> as a parameter.</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">getPosts</span><span class=\"p\">(</span><span class=\"n\">completion</span><span class=\"p\">:</span> <span class=\"p\">@</span><span class=\"n\">escaping</span> <span class=\"p\">([</span><span class=\"n\">Post</span><span class=\"p\">])</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Void</span><span class=\"p\">)</span>\n</pre>\n</div><p>The escaping closure allows the compiler to continue on to other code&mdash;<strong>escaping the method</strong>&mdash;and return later on when the data is ready to be returned.</p><h2>Constructing The Request</h2><div class=\"action\">\n<p>\nAdd the following lines in the body of <code>getPosts(completion:)</code></p>\n<pre><span class=\"c1\">// our API query</span>\n<span class=\"kd\">let</span> <span class=\"nv\">query</span> <span class=\"p\">=</span> <span class=\"s\">\"posts/all?sort_by=votes_count&amp;order=desc&amp;search[featured]=true&amp;per_page=20\"</span>\n<span class=\"c1\">// Add the baseURL to it</span>\n<span class=\"kd\">let</span> <span class=\"nv\">fullURL</span> <span class=\"p\">=</span> <span class=\"n\">URL</span><span class=\"p\">(</span><span class=\"n\">string</span><span class=\"p\">:</span> <span class=\"n\">baseURL</span> <span class=\"o\">+</span> <span class=\"n\">query</span><span class=\"p\">)</span><span class=\"o\">!</span>\n<span class=\"c1\">// Create the request</span>\n<span class=\"kd\">var</span> <span class=\"nv\">request</span> <span class=\"p\">=</span> <span class=\"n\">URLRequest</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">:</span> <span class=\"n\">fullURL</span><span class=\"p\">)</span>\n</pre>\n</div><p>This uses the <code>baseURL</code> of the API in addition to the parameters we established earlier to construct a request instance.</p><p>We'll configure the request before we send it off.</p><div class=\"action\">\n<p>\nAdd these lines underneath the previous 3 for <code>getPosts(completion:)</code></p>\n<pre><span class=\"p\">...</span>\n\n<span class=\"c1\">// We're sending a GET request, so we need to specify that</span>\n<span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">httpMethod</span> <span class=\"p\">=</span> <span class=\"s\">\"GET\"</span>\n<span class=\"c1\">// Add in all the header fields just like we did in Postman</span>\n<span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">allHTTPHeaderFields</span> <span class=\"p\">=</span> <span class=\"p\">[</span>\n   <span class=\"s\">\"Accept\"</span><span class=\"p\">:</span> <span class=\"s\">\"application/json\"</span><span class=\"p\">,</span>\n   <span class=\"s\">\"Content-Type\"</span><span class=\"p\">:</span> <span class=\"s\">\"application/json\"</span><span class=\"p\">,</span>\n   <span class=\"s\">\"Authorization\"</span><span class=\"p\">:</span> <span class=\"s\">\"Bearer </span><span class=\"si\">\\(</span><span class=\"n\">token</span><span class=\"si\">)</span><span class=\"s\">\"</span><span class=\"p\">,</span>\n   <span class=\"s\">\"Host\"</span><span class=\"p\">:</span> <span class=\"s\">\"api.producthunt.com\"</span>\n<span class=\"p\">]</span>\n</pre>\n</div><p>To send the request we'll use the <a href=\"https://developer.apple.com/documentation/foundation/urlsession/1411554-datatask\" target=\"_blank\">dataTask</a> method on our <code>urlSession</code></p><div class=\"action\">\n<p>\nAdd the following to the bottom of <code>getPosts</code></p>\n<pre>  <span class=\"p\">...</span>\n\n  <span class=\"kd\">let</span> <span class=\"nv\">task</span> <span class=\"p\">=</span> <span class=\"n\">urlSession</span><span class=\"p\">.</span><span class=\"n\">dataTask</span><span class=\"p\">(</span><span class=\"n\">with</span><span class=\"p\">:</span> <span class=\"n\">request</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">error</span> <span class=\"k\">in</span>\n\n  <span class=\"p\">}</span>\n\n</pre>\n</div><p>The <code>dataTask</code> method executes the <code>request</code> provided and the completion handler returns the result as <code>data</code>, a <code>response</code>, and an <code>error</code> if there is any reasons for an incomplete request. This method returns us a <code>URLSessionDataTask</code> object (<code>task</code>) which we can invoke <code>cancel()</code>, <code>suspend()</code> or <code>resume()</code>. We can also check its progress.</p><p>We'll check to see if there is an error first and then if there is any data to <strong>decode</strong>.</p><div class=\"action\">\n<p>\nAdd the following inside the <code>dataTask(with:)</code> completion handler</p>\n<pre><span class=\"kd\">let</span> <span class=\"nv\">task</span> <span class=\"p\">=</span> <span class=\"n\">urlSession</span><span class=\"p\">.</span><span class=\"n\">dataTask</span><span class=\"p\">(</span><span class=\"n\">with</span><span class=\"p\">:</span> <span class=\"n\">request</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">error</span> <span class=\"k\">in</span>\n   <span class=\"c1\">// error check/handling</span>\n   <span class=\"k\">if</span> <span class=\"kd\">let</span> <span class=\"nv\">error</span> <span class=\"p\">=</span> <span class=\"n\">error</span> <span class=\"p\">{</span>\n       <span class=\"bp\">print</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">.</span><span class=\"n\">localizedDescription</span><span class=\"p\">)</span>\n       <span class=\"k\">return</span>\n   <span class=\"p\">}</span>\n\n   <span class=\"c1\">// make sure we get back data</span>\n   <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">data</span> <span class=\"p\">=</span> <span class=\"n\">data</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n       <span class=\"k\">return</span>\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>These lines make sure that we have data to work with and that no error occurred. If either of those are not true, then we return.</p><p>Once we get past those checkpoints, we can decode the data.</p><div class=\"action\">\n<p>\nUse <code>JSONDecoder</code> to decode the data retrieved into a <code>PostList</code></p>\n<pre><span class=\"kd\">let</span> <span class=\"nv\">task</span> <span class=\"p\">=</span> <span class=\"n\">urlSession</span><span class=\"p\">.</span><span class=\"n\">dataTask</span><span class=\"p\">(</span><span class=\"n\">with</span><span class=\"p\">:</span> <span class=\"n\">request</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">error</span> <span class=\"k\">in</span>\n   <span class=\"p\">...</span>\n\n   <span class=\"c1\">// Decode the API response into our PostList object that we can use/interact with</span>\n   <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">result</span> <span class=\"p\">=</span> <span class=\"k\">try</span><span class=\"p\">?</span> <span class=\"n\">JSONDecoder</span><span class=\"p\">().</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"n\">PostList</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">from</span><span class=\"p\">:</span> <span class=\"n\">data</span><span class=\"p\">)</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n       <span class=\"k\">return</span>\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><!-- --><div class=\"info\">\n<p>\n<code>JSONDecoder().decode</code> automatically decodes any <code>Decodable</code>.</p>\n</div><p>If the <code>Post</code> is modeled correctly, <code>JSONDecoder().decode(...)</code> will continue on to the next step: returning the result as an array of posts!</p><div class=\"action\">\n<p>\nAdd the following to the bottom of the <code>dataTask</code> completion Handler</p>\n<pre><span class=\"kd\">let</span> <span class=\"nv\">task</span> <span class=\"p\">=</span> <span class=\"n\">urlSession</span><span class=\"p\">.</span><span class=\"n\">dataTask</span><span class=\"p\">(</span><span class=\"n\">with</span><span class=\"p\">:</span> <span class=\"n\">request</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">error</span> <span class=\"k\">in</span>\n   <span class=\"p\">...</span>\n\n   <span class=\"kd\">let</span> <span class=\"nv\">posts</span> <span class=\"p\">=</span> <span class=\"n\">result</span><span class=\"p\">.</span><span class=\"n\">posts</span>\n\n   <span class=\"c1\">// Return the result with the completion handler.</span>\n   <span class=\"n\">DispatchQueue</span><span class=\"p\">.</span><span class=\"n\">main</span><span class=\"p\">.</span><span class=\"n\">async</span> <span class=\"p\">{</span>\n       <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">posts</span><span class=\"p\">)</span>\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Since our <code>getPosts(...)</code> method performs a network call on a separate queue &ndash; a <strong>background queue</strong> &ndash; we therefore need to execute our completion handler on the <strong>main queue</strong> since all UI code must execute on the main queue.</p><div class=\"info\">\n<p>\nWe use the <strong>main queue</strong> for UI-related tasks, whereas any other time-consuming tasks should run on <strong>background queues</strong>. This is done so that the UI doesn't freeze up for the user while the app is running other tasks.</p>\n</div><p>One last thing we need to do is resume the <code>dataTask</code>. By default, <code>dataTasks</code> are paused. We'll have to resume it to start the task:</p><div class=\"action\">\n<p></p>\n<pre><span class=\"kd\">let</span> <span class=\"nv\">task</span> <span class=\"p\">=</span> <span class=\"n\">urlSession</span><span class=\"p\">.</span><span class=\"n\">dataTask</span><span class=\"p\">(</span><span class=\"n\">with</span><span class=\"p\">:</span> <span class=\"n\">request</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">error</span> <span class=\"k\">in</span>\n    <span class=\"p\">...</span>\n\n<span class=\"p\">}</span>\n\n<span class=\"n\">task</span><span class=\"p\">.</span><span class=\"n\">resume</span><span class=\"p\">()</span>\n</pre>\n</div><p>Networking layer is now complete (for now) &#128076;</p><div class=\"solution\">\n<p></p>\n<pre><span class=\"kd\">class</span> <span class=\"nc\">NetworkManager</span> <span class=\"p\">{</span>\n <span class=\"kd\">let</span> <span class=\"nv\">urlSession</span> <span class=\"p\">=</span> <span class=\"n\">URLSession</span><span class=\"p\">.</span><span class=\"n\">shared</span>\n <span class=\"kd\">var</span> <span class=\"nv\">baseURL</span> <span class=\"p\">=</span> <span class=\"s\">\"https://api.producthunt.com/v1/\"</span>\n <span class=\"kd\">var</span> <span class=\"nv\">token</span> <span class=\"p\">=</span> <span class=\"s\">\"replace-me-with-your-token-from-product-hunt-api-dashboard-&#128591;\"</span>\n\n <span class=\"kd\">func</span> <span class=\"nf\">getPosts</span><span class=\"p\">(</span><span class=\"n\">completion</span><span class=\"p\">:</span> <span class=\"p\">@</span><span class=\"n\">escaping</span> <span class=\"p\">([</span><span class=\"n\">Post</span><span class=\"p\">])</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n   <span class=\"c1\">// Construct the URL to get posts from API.</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">query</span> <span class=\"p\">=</span> <span class=\"s\">\"posts/all?sort_by=votes_count&amp;order=desc&amp;search[featured]=true&amp;per_page=20\"</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">fullURL</span> <span class=\"p\">=</span> <span class=\"n\">URL</span><span class=\"p\">(</span><span class=\"n\">string</span><span class=\"p\">:</span> <span class=\"n\">baseURL</span> <span class=\"o\">+</span> <span class=\"n\">query</span><span class=\"p\">)</span><span class=\"o\">!</span>\n   <span class=\"kd\">var</span> <span class=\"nv\">request</span> <span class=\"p\">=</span> <span class=\"n\">URLRequest</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">:</span> <span class=\"n\">fullURL</span><span class=\"p\">)</span>\n\n   <span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">httpMethod</span> <span class=\"p\">=</span> <span class=\"s\">\"GET\"</span>\n   <span class=\"c1\">// Set up header with API Token.</span>\n   <span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">allHTTPHeaderFields</span> <span class=\"p\">=</span> <span class=\"p\">[</span>\n     <span class=\"s\">\"Accept\"</span><span class=\"p\">:</span> <span class=\"s\">\"application/json\"</span><span class=\"p\">,</span>\n     <span class=\"s\">\"Content-Type\"</span><span class=\"p\">:</span> <span class=\"s\">\"application/json\"</span><span class=\"p\">,</span>\n     <span class=\"s\">\"Authorization\"</span><span class=\"p\">:</span> <span class=\"s\">\"Bearer </span><span class=\"si\">\\(</span><span class=\"n\">token</span><span class=\"si\">)</span><span class=\"s\">\"</span><span class=\"p\">,</span>\n     <span class=\"s\">\"Host\"</span><span class=\"p\">:</span> <span class=\"s\">\"api.producthunt.com\"</span>\n   <span class=\"p\">]</span>\n\n   <span class=\"kd\">let</span> <span class=\"nv\">task</span> <span class=\"p\">=</span> <span class=\"n\">urlSession</span><span class=\"p\">.</span><span class=\"n\">dataTask</span><span class=\"p\">(</span><span class=\"n\">with</span><span class=\"p\">:</span> <span class=\"n\">request</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">error</span> <span class=\"k\">in</span>\n     <span class=\"c1\">// Check for errors.</span>\n     <span class=\"k\">if</span> <span class=\"kd\">let</span> <span class=\"nv\">error</span> <span class=\"p\">=</span> <span class=\"n\">error</span> <span class=\"p\">{</span>\n       <span class=\"bp\">print</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">)</span>\n       <span class=\"k\">return</span>\n     <span class=\"p\">}</span>\n\n     <span class=\"c1\">// Check to see if there is any data that was retrieved.</span>\n     <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">data</span> <span class=\"p\">=</span> <span class=\"n\">data</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n       <span class=\"k\">return</span>\n     <span class=\"p\">}</span>\n\n     <span class=\"c1\">// Attempt to decode the data.</span>\n     <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">result</span> <span class=\"p\">=</span> <span class=\"k\">try</span><span class=\"p\">?</span> <span class=\"n\">JSONDecoder</span><span class=\"p\">().</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"n\">PostList</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">from</span><span class=\"p\">:</span> <span class=\"n\">data</span><span class=\"p\">)</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n       <span class=\"k\">return</span>\n     <span class=\"p\">}</span>\n\n     <span class=\"kd\">let</span> <span class=\"nv\">posts</span> <span class=\"p\">=</span> <span class=\"n\">result</span><span class=\"p\">.</span><span class=\"n\">posts</span>\n\n     <span class=\"c1\">// Return the result with the completion handler.</span>\n     <span class=\"n\">DispatchQueue</span><span class=\"p\">.</span><span class=\"n\">main</span><span class=\"p\">.</span><span class=\"n\">async</span> <span class=\"p\">{</span>\n         <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">posts</span><span class=\"p\">)</span>\n     <span class=\"p\">}</span>\n   <span class=\"p\">}</span>\n\n   <span class=\"n\">task</span><span class=\"p\">.</span><span class=\"n\">resume</span><span class=\"p\">()</span>\n <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Alright! We just learned <strong>how to build a network layer in Swift!</strong> Now we can start removing our mock data and put in real data from Product Hunt!</p><p>Let's use our <code>getPosts(...)</code> method in the <code>FeedViewController</code> to do so! But first...</p>"},{"id":"T0E6OlNlY3Rpb24tMTIxMDk=","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Created networking layer'</span>\n$ git push\n</pre>"}]},"next":{"id":"T0E6OlBhZ2UtMTYzNQ==","slug":"finish-feed-view","title":"Finishing Feed View"},"previous":{"id":"T0E6OlBhZ2UtMTYzNQ==","slug":"finish-feed-view","title":"Finishing Feed View"}},{"id":"T0E6OlBhZ2UtMTYzNQ==","title":"Finishing Feed View","slug":"finish-feed-view","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzg4OA==","title":"Finishing Feed View","htmlContent":"<ol>\n<li><del>Look at the Product Hunt API</del></li>\n<li><del>Build the Feed View</del></li>\n<li><del>Create the Post Model</del></li>\n<li><del>Build the Post Cell</del></li>\n<li><del>Create the Post Cell Class</del></li>\n<li><del>Test the Feed Table View</del></li>\n<li><del>Allow the Post Model to work with network requests</del></li>\n<li><del>Create the network layer</del></li>\n<li>\n<strong>Retrieve data from the PH API</strong>\n\n<ol>\n<li><strong>Replace the mock data with real data</strong></li>\n<li><strong>Update Posts List With NetworkManager</strong></li>\n</ol>\n</li>\n<li>Build the Comments View</li>\n<li>Pull Comments data from the API</li>\n<li>Update the view controllers to hook everything up</li>\n</ol><p>Now that the network manager is complete, we can retrieve real data from Product Hunt through their API!</p><p>The next step would be to tie it in with our UI and have the main feature of our app (browsing featured products on Product Hunt) completed.</p><p>Let's start by adding a <code>NetworkManager</code> to <code>FeedViewController</code></p><div class=\"action\">\n<p>\nOpen <code>FeedViewController.swift</code> and add a <code>NetworkManager</code> property below your <code>mockData</code> list.</p>\n<pre><span class=\"kd\">var</span> <span class=\"nv\">mockData</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"n\">Post</span><span class=\"p\">]</span> <span class=\"p\">=</span> <span class=\"p\">{</span>\n    <span class=\"p\">...</span>\n<span class=\"p\">}()</span>\n\n<span class=\"kd\">var</span> <span class=\"nv\">networkManager</span> <span class=\"p\">=</span> <span class=\"n\">NetworkManager</span><span class=\"p\">()</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzg4OQ==","title":"Replace Mock Data","htmlContent":"<p>Now we can replace <code>mockData</code> with the list that will be holding the products retrieved from the API.</p><div class=\"action\">\n<p>\nReplace the <code>mockData</code> list with an empty <code>posts</code> list.</p>\n<pre><span class=\"p\">...</span>\n\n<span class=\"kd\">var</span> <span class=\"nv\">posts</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"n\">Post</span><span class=\"p\">]</span> <span class=\"p\">=</span> <span class=\"p\">[]</span>\n\n<span class=\"p\">...</span>\n</pre>\n</div><p>We can use another property observer here to update the <code>feedTableView</code> every time the <code>posts</code> is updated.</p><div class=\"action\">\n<p>\nAdd a <code>didSet</code> property observer to <code>posts</code> to update the view.</p>\n<pre><span class=\"kd\">var</span> <span class=\"nv\">posts</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"n\">Post</span><span class=\"p\">]</span> <span class=\"p\">=</span> <span class=\"p\">[]</span> <span class=\"p\">{</span>\n   <span class=\"kr\">didSet</span> <span class=\"p\">{</span>\n       <span class=\"n\">feedTableView</span><span class=\"p\">.</span><span class=\"n\">reloadData</span><span class=\"p\">()</span>\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Next we'll update the places where <code>mockData</code> was used to use our newly created <code>posts</code> list.</p><div class=\"action\">\n<p>\nUpdate the the following methods in the <code>UITableViewDataSource</code> extension to use <code>posts</code> rather than <code>mockData</code> list.</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">numberOfRowsInSection</span> <span class=\"n\">section</span><span class=\"p\">:</span> <span class=\"nb\">Int</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Int</span> <span class=\"p\">{</span>\n <span class=\"c1\">// return the actual number of posts we receive</span>\n <span class=\"k\">return</span> <span class=\"n\">posts</span><span class=\"p\">.</span><span class=\"bp\">count</span>\n<span class=\"p\">}</span>\n\n<span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">cellForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n <span class=\"kd\">let</span> <span class=\"nv\">cell</span> <span class=\"p\">=</span> <span class=\"n\">tableView</span><span class=\"p\">.</span><span class=\"n\">dequeueReusableCell</span><span class=\"p\">(</span><span class=\"n\">withIdentifier</span><span class=\"p\">:</span> <span class=\"s\">\"postCell\"</span><span class=\"p\">,</span> <span class=\"k\">for</span><span class=\"p\">:</span> <span class=\"n\">indexPath</span><span class=\"p\">)</span> <span class=\"k\">as</span><span class=\"p\">!</span> <span class=\"n\">PostTableViewCell</span>\n\n <span class=\"c1\">// retrieve from the actual posts, and not mock data</span>\n <span class=\"kd\">let</span> <span class=\"nv\">post</span> <span class=\"p\">=</span> <span class=\"n\">posts</span><span class=\"p\">[</span><span class=\"n\">indexPath</span><span class=\"p\">.</span><span class=\"n\">row</span><span class=\"p\">]</span>\n <span class=\"n\">cell</span><span class=\"p\">.</span><span class=\"n\">post</span> <span class=\"p\">=</span> <span class=\"n\">post</span>\n <span class=\"k\">return</span> <span class=\"n\">cell</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Now we can tie everything together.</p>"},{"id":"T0E6OlNlY3Rpb24tNzg5MA==","title":"Update Posts List With NetworkManager","htmlContent":"<p>We'll use a method that runs inside <code>viewDidLoad</code> to update the feed of the app.</p><div class=\"action\">\n<p>\nCreate the method <code>updateFeed()</code> below <code>viewDidLoad()</code> method.</p>\n<pre><span class=\"p\">...</span>\n\n<span class=\"kd\">func</span> <span class=\"nf\">updateFeed</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n\n<span class=\"p\">}</span>\n</pre>\n</div><p>All we have to do is update the <code>posts</code> list with the data retrieved from a request to the API.</p><div class=\"action\">\n<p>\nUse <code>getPosts()</code> method to update <code>posts</code> list.</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">updateFeed</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// call our network manager's getPosts method to update our feed with posts</span>\n   <span class=\"n\">networkManager</span><span class=\"p\">.</span><span class=\"n\">getPosts</span><span class=\"p\">()</span> <span class=\"p\">{</span> <span class=\"n\">result</span> <span class=\"k\">in</span>\n       <span class=\"kc\">self</span><span class=\"p\">.</span><span class=\"n\">posts</span> <span class=\"p\">=</span> <span class=\"n\">result</span>\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n<p>Add <code>updateFeed()</code> at the bottom of <code>viewDidLoad()</code></p>\n<pre>   <span class=\"p\">...</span>\n\n   <span class=\"n\">updateFeed</span><span class=\"p\">()</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzg5MQ==","title":"Product So Far","htmlContent":"<p>That's it &#128079; Run the app to see it in action.</p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P09-Finishing-Feed-View/assets/01_update-posts-with_finished-feed-view.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P09-Finishing-Feed-View/assets/01_update-posts-with_finished-feed-view.png\" alt=\"Finished Feed View\" title=\"\">\n        </a></p><p>Notice that we still don't have images for each of the cells. If we look at <code>PostTableViewCell</code>, we're still using <code>placeholder</code> for our image. We'll revisit updating this towards the end of this tutorial, so don't worry about it for now!</p><p>Instead, celebrate the fact that not only did we apply our learning of <strong>how to build a network layer into Swift, decode JSON into Swift models, and work with APIs</strong>, but we also have now completed the first 2 user stories:</p><ul>\n<li>I can browse products featured today on Product Hunt by scrolling through the app&rsquo;s main screen.</li>\n<li>I see each product&rsquo;s name, tagline, number of votes.</li>\n</ul>"},{"id":"T0E6OlNlY3Rpb24tNzg5Mg==","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Users can browse products'</span>\n$ git push\n</pre><p>Let's move on to the final user story!</p>"}]},"next":{"id":"T0E6OlBhZ2UtMTYzNg==","slug":"comments-view","title":"Building The Comments View"},"previous":{"id":"T0E6OlBhZ2UtMTYzNg==","slug":"comments-view","title":"Building The Comments View"}},{"id":"T0E6OlBhZ2UtMTYzNg==","title":"Building The Comments View","slug":"comments-view","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzg5Mw==","title":"Building The Comments View","htmlContent":"<p>Now we can move on to the second part of the app. The <code>CommentsView</code> which will show the comments of a tapped product.</p><p>This view is much simpler than the <code>FeedView</code> and doesn't require much work to get it setup with the API, but we will be refactoring some of our code to improve its quality and reduce repetitive code.</p>"},{"id":"T0E6OlNlY3Rpb24tNzg5NA==","title":"Building The UI","htmlContent":"<p>The <code>CommentsView</code> is also a view which utilizes a <code>UITableView</code> with a custom made cell to display an array of information.</p><p>We'll start by creating both the view and the cell.</p><div class=\"action\">\n<p>\nOpen Storyboard and add a new <code>UIViewController</code> scene from the Object Library. Rename the <code>UIViewController</code> to be <code>Comments</code></p>\n\n<p>Add a <code>UITableView</code> to the <code>Comments UIViewController</code> and pin it to all sides of its view. Name it <code>Comments Table View</code>.</p>\n</div><p>The cell will consist of a single <code>UITextView</code> that fills the cell with padding on the sides.</p><div class=\"action\">\n<p></p>\n\n<p>Add a <code>UITableViewCell</code> with the <strong>identifier <code>commentCell</code></strong> to the <code>Comments Table View</code>. Go to the <strong>Size Inspector</strong> and give the cell a <strong>row height of 125</strong></p>\n\n<p>If you need a refresher on building and customizing a cell, review chapter 5 of this tutorial</p>\n\n<p>Next add a <strong><code>UITextView</code> to <code>commentCell</code> with 15 points of padding</strong> on all sides. Name it <code>Comments Text View</code>.</p>\n\n<p>At this point your Comments View should look like this:\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P10-Building-The-Comments-View/assets/01_building-the-ui_comments-view.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P10-Building-The-Comments-View/assets/01_building-the-ui_comments-view.png\" alt=\"Comments view with cell\" title=\"\">\n        </a></p>\n</div><p>Lastly, we don't want to make comments editable, so let's disable that for <code>Comments Text View</code>.</p><div class=\"action\">\n<p>\nDisable <code>Editable</code> behavior for the text-view in its <strong>Attribute Inspector</strong>.\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P10-Building-The-Comments-View/assets/02_building-the-ui_disable-editable.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P10-Building-The-Comments-View/assets/02_building-the-ui_disable-editable.png\" alt=\"Disable Editable\" title=\"\">\n        </a></p>\n</div><p>And that's it! We've got our comments view! Now let's wire it up.</p>"},{"id":"T0E6OlNlY3Rpb24tNzg5NQ==","title":"Create CommentsViewController","htmlContent":"<p>Setting up the <code>CommentsViewController</code> is going to be very similar to what we've already done for <code>FeedViewController</code>. We'll go through what's needed for the setup, but you'll be writing the code yourself based on the instructions. If you get stuck, look at the work you did for <code>FeedViewController</code> and see how it can map over to <code>CommentsViewController</code>.</p><div class=\"action\">\n<p>\nFirst step is to create a new <code>UIViewController</code> class (remember to use a <code>Cocoa Touch Class</code> file), and name it <code>CommentsViewController</code></p>\n</div><h2>Connect the storyboard items to the view-controller.</h2><div class=\"action\">\n<p>\nSet the class of the <code>Comments</code> view controller to <code>CommentsViewController</code> and its <code>Storyboard ID</code> to <code>commentsView</code> in the <code>Identity Inspector</code>.</p>\n</div><h2>Connect the table-view to the class.</h2><div class=\"action\">\n<p>\nCreate an <code>IBOutlet</code> for the <code>UITableView</code> named <code>commentsTableView</code>, then set its <code>delegate</code> and <code>dataSource</code> to <code>self</code> in the <code>viewDidLoad</code> method.</p>\n</div><p>Create an implicitly unwrapped optional array of strings to hold the comments and updates the table-view.</p><div class=\"action\">\n<p>\nAdd variable <code>var comments: [String]!</code> to <code>CommentsViewController</code> with a <code>didSet</code> property observer. We'll leave this blank for now, but once we add real data, we'll need to have it refresh the <code>commentsTableView</code>.</p>\n</div><h2>Make TableView Functional</h2><p>Next we setup the necessary methods for our <code>commentsTableView</code> to work.</p><div class=\"action\">\n<p>\nCreate extensions for <code>CommentsViewController</code> which inherit from <code>UITableViewDataSource</code> and add the methods to pull information from the <code>comments</code> list</p>\n<pre><span class=\"c1\">// All methods here operate the same way we did for Posts</span>\n\n<span class=\"c1\">// </span><span class=\"cs\">MARK:</span><span class=\"c1\"> UITableViewDatasource</span>\n<span class=\"kd\">extension</span> <span class=\"nc\">CommentsViewController</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewDataSource</span> <span class=\"p\">{</span>\n<span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">numberOfRowsInSection</span> <span class=\"n\">section</span><span class=\"p\">:</span> <span class=\"nb\">Int</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Int</span> <span class=\"p\">{</span>\n   <span class=\"k\">return</span> <span class=\"n\">comments</span><span class=\"p\">.</span><span class=\"bp\">count</span>\n <span class=\"p\">}</span>\n\n <span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">cellForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">cell</span> <span class=\"p\">=</span> <span class=\"n\">tableView</span><span class=\"p\">.</span><span class=\"n\">dequeueReusableCell</span><span class=\"p\">(</span><span class=\"n\">withIdentifier</span><span class=\"p\">:</span> <span class=\"s\">\"commentCell\"</span><span class=\"p\">,</span> <span class=\"k\">for</span><span class=\"p\">:</span> <span class=\"n\">indexPath</span><span class=\"p\">)</span> <span class=\"k\">as</span><span class=\"p\">!</span> <span class=\"n\">CommentTableViewCell</span>\n\n   <span class=\"kd\">let</span> <span class=\"nv\">comment</span> <span class=\"p\">=</span> <span class=\"n\">comments</span><span class=\"p\">[</span><span class=\"n\">indexPath</span><span class=\"p\">.</span><span class=\"n\">row</span><span class=\"p\">]</span>\n   <span class=\"n\">cell</span><span class=\"p\">.</span><span class=\"n\">commentTextView</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"n\">comment</span>\n   <span class=\"k\">return</span> <span class=\"n\">cell</span>\n <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// </span><span class=\"cs\">MARK:</span><span class=\"c1\"> UITableViewDelegate</span>\n<span class=\"kd\">extension</span> <span class=\"nc\">CommentsViewController</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewDelegate</span> <span class=\"p\">{</span>\n    <span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">heightForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"n\">CGFloat</span> <span class=\"p\">{</span>\n        <span class=\"k\">return</span> <span class=\"mi\">125</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Next we'll create the <code>CommentTableViewCell</code> that will allow the last method to work with a custom cell.</p>"},{"id":"T0E6OlNlY3Rpb24tNzg5Ng==","title":"Create CommentTableViewCell","htmlContent":"<p>This cell is much simpler and requires very little code.</p><div class=\"action\">\n<p>\nCreate a new <code>UITableViewCell</code> class named <code>CommentTableViewCell</code>. Set <code>commentCell</code> to this new class.</p>\n\n<p>Once the class has been updated, Connect an <code>IBOutlet</code> from <code>Comments Text View</code> to <code>CommentTableViewCell</code>.</p>\n<pre><span class=\"kd\">class</span> <span class=\"nc\">CommentTableViewCell</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n  <span class=\"kr\">@IBOutlet</span> <span class=\"kr\">weak</span> <span class=\"kd\">var</span> <span class=\"nv\">commentTextView</span><span class=\"p\">:</span> <span class=\"bp\">UITextView</span><span class=\"p\">!</span>\n<span class=\"p\">}</span>\n</pre>\n<p>All this cell class needs is one line for the <code>IBOutlet</code>.</p>\n</div><p>Now we can test it with mock data.</p>"},{"id":"T0E6OlNlY3Rpb24tNzg5Nw==","title":"Connect The Views","htmlContent":"<p>Now we can setup the tap handler for our table-view to present the comments of a post.</p><p>The method that allows us to do this is from the <code>UITableViewDelegate</code> which gives us access to the cell that a user selects.</p><p>Navigate to <code>FeedViewController.swift</code> and add the following:</p><div class=\"action\">\n<p>\nAdd the <code>tableView(tableView: didSelectRowAt:)</code> method to the <code>UITableViewDelegate</code> extension in <code>FeedViewController</code>.</p>\n<pre><span class=\"p\">...</span>\n<span class=\"kd\">extension</span> <span class=\"nc\">FeedViewController</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewDelegate</span> <span class=\"p\">{</span>\n    <span class=\"p\">...</span>\n\n    <span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">didSelectRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n       <span class=\"kd\">let</span> <span class=\"nv\">post</span> <span class=\"p\">=</span> <span class=\"n\">posts</span><span class=\"p\">[</span><span class=\"n\">indexPath</span><span class=\"p\">.</span><span class=\"n\">row</span><span class=\"p\">]</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>We don't have the method necessary to get the comments of a post, so instead we'll use mock data to to test how everything looks first.</p><div class=\"action\">\n<p>\nAdd this to <code>tableView(tableView: didSelectRowAt:)</code> method to present a <code>CommentsViewController</code> with fake comments.</p>\n<pre> <span class=\"p\">...</span>\n\n<span class=\"c1\">// Get the storyboard</span>\n <span class=\"kd\">let</span> <span class=\"nv\">storyboard</span> <span class=\"p\">=</span> <span class=\"bp\">UIStoryboard</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">:</span> <span class=\"s\">\"Main\"</span><span class=\"p\">,</span> <span class=\"n\">bundle</span><span class=\"p\">:</span> <span class=\"n\">Bundle</span><span class=\"p\">.</span><span class=\"n\">main</span><span class=\"p\">)</span>\n<span class=\"c1\">// Get the commentsView from the storyboard</span>\n <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">commentsView</span> <span class=\"p\">=</span> <span class=\"n\">storyboard</span><span class=\"p\">.</span><span class=\"n\">instantiateViewController</span><span class=\"p\">(</span><span class=\"n\">withIdentifier</span><span class=\"p\">:</span> <span class=\"s\">\"commentsView\"</span><span class=\"p\">)</span> <span class=\"k\">as</span><span class=\"p\">?</span> <span class=\"n\">CommentsViewController</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n   <span class=\"k\">return</span>\n <span class=\"p\">}</span>\n <span class=\"c1\">// add mock comments</span>\n <span class=\"n\">commentsView</span><span class=\"p\">.</span><span class=\"n\">comments</span> <span class=\"p\">=</span> <span class=\"p\">[</span><span class=\"s\">\"Blah blah blah!\"</span><span class=\"p\">,</span> <span class=\"s\">\"Good app.\"</span><span class=\"p\">,</span> <span class=\"s\">\"Wow.\"</span><span class=\"p\">]</span>\n <span class=\"n\">navigationController</span><span class=\"p\">?.</span><span class=\"n\">pushViewController</span><span class=\"p\">(</span><span class=\"n\">commentsView</span><span class=\"p\">,</span> <span class=\"n\">animated</span><span class=\"p\">:</span> <span class=\"kc\">true</span><span class=\"p\">)</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzg5OA==","title":"Product So Far","htmlContent":"<p>Run the app and test it out to see how it looks!\n<a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P10-Building-The-Comments-View/assets/03_connect-the-views_mock-comments.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P10-Building-The-Comments-View/assets/03_connect-the-views_mock-comments.png\" alt=\"Mock Comments Finished\" title=\"\">\n        </a></p><p>You can check your implementation with the below solutions for <code>CommentTableViewCell</code> and <code>CommentsViewController</code>:</p><div class=\"solution\">\n<p>\n <strong>CommentTableViewCell</strong></p>\n<pre> <span class=\"kd\">import</span> <span class=\"nc\">UIKit</span>\n\n<span class=\"kd\">class</span> <span class=\"nc\">CommentTableViewCell</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n    <span class=\"kr\">@IBOutlet</span> <span class=\"kr\">weak</span> <span class=\"kd\">var</span> <span class=\"nv\">commentTextView</span><span class=\"p\">:</span> <span class=\"bp\">UITextView</span><span class=\"p\">!</span>\n\n  <span class=\"c1\">// Below functions are not needed, they were auto-generated</span>\n    <span class=\"kr\">override</span> <span class=\"kd\">func</span> <span class=\"nf\">awakeFromNib</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n        <span class=\"kc\">super</span><span class=\"p\">.</span><span class=\"n\">awakeFromNib</span><span class=\"p\">()</span>\n        <span class=\"c1\">// Initialization code</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"kr\">override</span> <span class=\"kd\">func</span> <span class=\"nf\">setSelected</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">selected</span><span class=\"p\">:</span> <span class=\"nb\">Bool</span><span class=\"p\">,</span> <span class=\"n\">animated</span><span class=\"p\">:</span> <span class=\"nb\">Bool</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n        <span class=\"kc\">super</span><span class=\"p\">.</span><span class=\"n\">setSelected</span><span class=\"p\">(</span><span class=\"n\">selected</span><span class=\"p\">,</span> <span class=\"n\">animated</span><span class=\"p\">:</span> <span class=\"n\">animated</span><span class=\"p\">)</span>\n\n        <span class=\"c1\">// Configure the view for the selected state</span>\n    <span class=\"p\">}</span>\n\n<span class=\"p\">}</span>\n</pre>\n<p><strong>CommentsViewController</strong></p>\n<pre><span class=\"kd\">import</span> <span class=\"nc\">UIKit</span>\n\n<span class=\"kd\">class</span> <span class=\"nc\">CommentsViewController</span><span class=\"p\">:</span> <span class=\"bp\">UIViewController</span> <span class=\"p\">{</span>\n\n    <span class=\"kr\">@IBOutlet</span> <span class=\"kr\">weak</span> <span class=\"kd\">var</span> <span class=\"nv\">commentsTableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">!</span>\n\n    <span class=\"kd\">var</span> <span class=\"nv\">comments</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"nb\">String</span><span class=\"p\">]</span><span class=\"o\">!</span> <span class=\"p\">{</span>\n        <span class=\"kr\">didSet</span> <span class=\"p\">{</span>\n            <span class=\"c1\">// </span><span class=\"cs\">TODO:</span><span class=\"c1\"> fill in later when we have real data</span>\n        <span class=\"p\">}</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"kr\">override</span> <span class=\"kd\">func</span> <span class=\"nf\">viewDidLoad</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n        <span class=\"kc\">super</span><span class=\"p\">.</span><span class=\"n\">viewDidLoad</span><span class=\"p\">()</span>\n        <span class=\"n\">commentsTableView</span><span class=\"p\">.</span><span class=\"n\">dataSource</span> <span class=\"p\">=</span> <span class=\"kc\">self</span>\n        <span class=\"n\">commentsTableView</span><span class=\"p\">.</span><span class=\"n\">delegate</span> <span class=\"p\">=</span> <span class=\"kc\">self</span>\n    <span class=\"p\">}</span>\n\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// </span><span class=\"cs\">MARK:</span><span class=\"c1\"> UITableViewDatasource</span>\n<span class=\"kd\">extension</span> <span class=\"nc\">CommentsViewController</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewDataSource</span> <span class=\"p\">{</span>\n    <span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">numberOfRowsInSection</span> <span class=\"n\">section</span><span class=\"p\">:</span> <span class=\"nb\">Int</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Int</span> <span class=\"p\">{</span>\n        <span class=\"k\">return</span> <span class=\"n\">comments</span><span class=\"p\">.</span><span class=\"bp\">count</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">cellForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n        <span class=\"kd\">let</span> <span class=\"nv\">cell</span> <span class=\"p\">=</span> <span class=\"n\">tableView</span><span class=\"p\">.</span><span class=\"n\">dequeueReusableCell</span><span class=\"p\">(</span><span class=\"n\">withIdentifier</span><span class=\"p\">:</span> <span class=\"s\">\"commentCell\"</span><span class=\"p\">,</span> <span class=\"k\">for</span><span class=\"p\">:</span> <span class=\"n\">indexPath</span><span class=\"p\">)</span> <span class=\"k\">as</span><span class=\"p\">!</span> <span class=\"n\">CommentTableViewCell</span>\n\n        <span class=\"kd\">let</span> <span class=\"nv\">comment</span> <span class=\"p\">=</span> <span class=\"n\">comments</span><span class=\"p\">[</span><span class=\"n\">indexPath</span><span class=\"p\">.</span><span class=\"n\">row</span><span class=\"p\">]</span>\n        <span class=\"n\">cell</span><span class=\"p\">.</span><span class=\"n\">commentTextView</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"n\">comment</span>\n        <span class=\"k\">return</span> <span class=\"n\">cell</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n<span class=\"c1\">// </span><span class=\"cs\">MARK:</span><span class=\"c1\"> UITableViewDelegate</span>\n<span class=\"kd\">extension</span> <span class=\"nc\">CommentsViewController</span><span class=\"p\">:</span> <span class=\"bp\">UITableViewDelegate</span> <span class=\"p\">{</span>\n    <span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">heightForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"n\">CGFloat</span> <span class=\"p\">{</span>\n        <span class=\"k\">return</span> <span class=\"mi\">125</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>We've gotten more practice at <strong>displaying data in tableviews with custom UI</strong> as well as with <strong>using mock data</strong> to stub views out! Let's fix up our network layer to not only make our code more efficient, but also to include pulling in comment data!</p>"},{"id":"T0E6OlNlY3Rpb24tNzg5OQ==","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Built Comments view and controller'</span>\n$ git push\n</pre>"}]},"next":{"id":"T0E6OlBhZ2UtMTYzNw==","slug":"networking-layer","title":"Reconstructing Networking Layer"},"previous":{"id":"T0E6OlBhZ2UtMTYzNw==","slug":"networking-layer","title":"Reconstructing Networking Layer"}},{"id":"T0E6OlBhZ2UtMTYzNw==","title":"Reconstructing Networking Layer","slug":"networking-layer","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzE5MQ==","title":"Reconstructing Networking Layer","htmlContent":"<p>Now that we have a working <code>CommentsViewController</code> the next step will be to build the methods necessary to pull data from the API.</p><p>Going back to the <a href=\"https://api.producthunt.com/v1/docs\" target=\"_blank\">API documentation</a>, you'll find how to send a pull request to retrieve a specific post's comments.</p><div class=\"action\">\n<p>\nOpen Postman and send a <strong>GET</strong> request with this URL\n<code>https://api.producthunt.com/v1/comments?sory_by=votes&amp;order=asc&amp;per_page=20&amp;search[post_id]=1</code></p>\n\n<p><strong>Note:</strong> be sure to use the same request sent with the correct headers such as authorization or this request will not work</p>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE5Mg==","title":"Create Comment Model","htmlContent":"<p>Let's start by creating the model that will hold the <strong>id</strong> and <strong>body</strong> of a comment retrieved from the API.</p><div class=\"action\">\n<p>\nCreate a <code>Decodable</code> model called <code>Comment</code> with an <code>Int id</code> and <code>String body</code>.</p>\n<pre><span class=\"kd\">struct</span> <span class=\"nc\">Comment</span><span class=\"p\">:</span> <span class=\"n\">Decodable</span> <span class=\"p\">{</span>\n <span class=\"kd\">let</span> <span class=\"nv\">id</span><span class=\"p\">:</span> <span class=\"nb\">Int</span>\n <span class=\"kd\">let</span> <span class=\"nv\">body</span><span class=\"p\">:</span> <span class=\"nb\">String</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>And the <code>struct</code> to represent the API response from the pull request.</p><div class=\"action\">\n<p>\nCreate the <code>CommentApiResponse</code> struct within your <code>Comment</code> model that has a list of <code>Comment</code> objects to model the JSON we will retrieve from the API. This will need to be <code>Decodable</code> as well.</p>\n<pre><span class=\"kd\">struct</span> <span class=\"nc\">CommentApiResponse</span><span class=\"p\">:</span> <span class=\"n\">Decodable</span> <span class=\"p\">{</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">comments</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"n\">Comment</span><span class=\"p\">]</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Because our variables match the properties of the JSON retrieved from the API we do not need to set up coding keys or an initializer. The Comment model is ready to go &#128077;</p>"},{"id":"T0E6OlNlY3Rpb24tNzE5Mw==","title":"EndPoints","htmlContent":"<p>We'll do some major refactoring to the networking layer to improve the overall quality of the code and reduce repetitive code.</p><p>Using <code>enums</code> is a great way to do this. An <strong>enumeration</strong> defines a common type for a group of related values and gives us access to those values in a way that is type-safe.</p><div class=\"info\">\n<p>\nSomething is considered <strong>type-safe</strong> if an operation checks that it can be performed on a specific data type before it attempts to do so. For example, preventing a function from calling the <code>append</code> method on an <code>Int</code> before it actually executes the call.</p>\n</div><p>We'll have a case for each endpoint from the API that we want to access.</p><div class=\"action\">\n<p>\nCreate enum <code>EndPoints</code> with cases for <code>posts</code> and <code>comments</code> inside the <code>NetworkManager</code> class</p>\n<pre><span class=\"kd\">class</span> <span class=\"nc\">NetworkManager</span> <span class=\"p\">{</span>\n<span class=\"p\">...</span>\n  <span class=\"kd\">enum</span> <span class=\"nc\">EndPoints</span> <span class=\"p\">{</span>\n   <span class=\"k\">case</span> <span class=\"n\">posts</span>\n   <span class=\"k\">case</span> <span class=\"n\">comments</span><span class=\"p\">(</span><span class=\"n\">postId</span><span class=\"p\">:</span> <span class=\"nb\">Int</span><span class=\"p\">)</span>\n  <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>We'll have a method for each part of the <code>URLRequest</code> necessary to build the pull request to get posts and comments.</p><div class=\"action\">\n<p>\n Create a method <strong>get the path</strong> of the posts and comments.</p>\n<pre><span class=\"kd\">enum</span> <span class=\"nc\">EndPoints</span> <span class=\"p\">{</span>\n  <span class=\"p\">...</span>\n  <span class=\"c1\">// determine which path to provide for the API request</span>\n  <span class=\"kd\">func</span> <span class=\"nf\">getPath</span><span class=\"p\">()</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">String</span> <span class=\"p\">{</span>\n      <span class=\"k\">switch</span> <span class=\"kc\">self</span> <span class=\"p\">{</span>\n      <span class=\"k\">case</span> <span class=\"p\">.</span><span class=\"n\">posts</span><span class=\"p\">:</span>\n          <span class=\"k\">return</span> <span class=\"s\">\"posts/all\"</span>\n      <span class=\"k\">case</span> <span class=\"p\">.</span><span class=\"n\">comments</span><span class=\"p\">:</span>\n          <span class=\"k\">return</span> <span class=\"s\">\"comments\"</span>\n      <span class=\"p\">}</span>\n  <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n<p>Create a method to get the <strong>http method</strong> in a type-safe way.</p>\n<pre><span class=\"kd\">enum</span> <span class=\"nc\">EndPoints</span> <span class=\"p\">{</span>\n <span class=\"p\">...</span>\n <span class=\"c1\">// We're only ever calling GET for now, but this could be built out if that were to change</span>\n <span class=\"kd\">func</span> <span class=\"nf\">getHTTPMethod</span><span class=\"p\">()</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">String</span> <span class=\"p\">{</span>\n   <span class=\"k\">return</span> <span class=\"s\">\"GET\"</span>\n <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n<p>Create method to get <strong>headers</strong>.</p>\n<pre><span class=\"kd\">enum</span> <span class=\"nc\">EndPoints</span> <span class=\"p\">{</span>\n <span class=\"p\">...</span>\n <span class=\"c1\">// Same headers we used for Postman</span>\n <span class=\"kd\">func</span> <span class=\"nf\">getHeaders</span><span class=\"p\">(</span><span class=\"n\">token</span><span class=\"p\">:</span> <span class=\"nb\">String</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"p\">[</span><span class=\"nb\">String</span><span class=\"p\">:</span> <span class=\"nb\">String</span><span class=\"p\">]</span> <span class=\"p\">{</span>\n   <span class=\"k\">return</span> <span class=\"p\">[</span>\n      <span class=\"s\">\"Accept\"</span><span class=\"p\">:</span> <span class=\"s\">\"application/json\"</span><span class=\"p\">,</span>\n     <span class=\"s\">\"Content-Type\"</span><span class=\"p\">:</span> <span class=\"s\">\"application/json\"</span><span class=\"p\">,</span>\n     <span class=\"s\">\"Authorization\"</span><span class=\"p\">:</span> <span class=\"s\">\"Bearer </span><span class=\"si\">\\(</span><span class=\"n\">token</span><span class=\"si\">)</span><span class=\"s\">\"</span><span class=\"p\">,</span>\n     <span class=\"s\">\"Host\"</span><span class=\"p\">:</span> <span class=\"s\">\"api.producthunt.com\"</span>\n   <span class=\"p\">]</span>\n <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n<p>Create method to get <strong>parameters</strong></p>\n<pre><span class=\"kd\">enum</span> <span class=\"nc\">EndPoints</span> <span class=\"p\">{</span>\n <span class=\"p\">...</span>\n <span class=\"c1\">// grab the parameters for the appropriate object (post or comment)</span>\n <span class=\"kd\">func</span> <span class=\"nf\">getParams</span><span class=\"p\">()</span> <span class=\"p\">-&gt;</span> <span class=\"p\">[</span><span class=\"nb\">String</span><span class=\"p\">:</span> <span class=\"nb\">String</span><span class=\"p\">]</span> <span class=\"p\">{</span>\n   <span class=\"k\">switch</span> <span class=\"kc\">self</span> <span class=\"p\">{</span>\n   <span class=\"k\">case</span> <span class=\"p\">.</span><span class=\"n\">posts</span><span class=\"p\">:</span>\n     <span class=\"k\">return</span> <span class=\"p\">[</span>\n       <span class=\"s\">\"sort_by\"</span><span class=\"p\">:</span> <span class=\"s\">\"votes_count\"</span><span class=\"p\">,</span>\n       <span class=\"s\">\"order\"</span><span class=\"p\">:</span> <span class=\"s\">\"desc\"</span><span class=\"p\">,</span>\n       <span class=\"s\">\"per_page\"</span><span class=\"p\">:</span> <span class=\"s\">\"20\"</span><span class=\"p\">,</span>\n\n       <span class=\"s\">\"search[featured]\"</span><span class=\"p\">:</span> <span class=\"s\">\"true\"</span>\n     <span class=\"p\">]</span>\n\n   <span class=\"k\">case</span> <span class=\"kd\">let</span> <span class=\"p\">.</span><span class=\"n\">comments</span><span class=\"p\">(</span><span class=\"n\">postId</span><span class=\"p\">):</span>\n     <span class=\"k\">return</span> <span class=\"p\">[</span>\n       <span class=\"s\">\"sort_by\"</span><span class=\"p\">:</span> <span class=\"s\">\"votes\"</span><span class=\"p\">,</span>\n       <span class=\"s\">\"order\"</span><span class=\"p\">:</span> <span class=\"s\">\"asc\"</span><span class=\"p\">,</span>\n       <span class=\"s\">\"per_page\"</span><span class=\"p\">:</span> <span class=\"s\">\"20\"</span><span class=\"p\">,</span>\n\n        <span class=\"s\">\"search[post_id]\"</span><span class=\"p\">:</span> <span class=\"s\">\"</span><span class=\"si\">\\(</span><span class=\"n\">postId</span><span class=\"si\">)</span><span class=\"s\">\"</span>\n      <span class=\"p\">]</span>\n   <span class=\"p\">}</span>\n <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n<p>Create method to convert the <strong>params</strong> array into a connected <strong>string</strong>.</p>\n<pre><span class=\"kd\">enum</span> <span class=\"nc\">EndPoints</span> <span class=\"p\">{</span>\n <span class=\"p\">...</span>\n <span class=\"kd\">func</span> <span class=\"nf\">paramsToString</span><span class=\"p\">()</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">String</span> <span class=\"p\">{</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">parameterArray</span> <span class=\"p\">=</span> <span class=\"n\">getParams</span><span class=\"p\">().</span><span class=\"bp\">map</span> <span class=\"p\">{</span> <span class=\"n\">key</span><span class=\"p\">,</span> <span class=\"n\">value</span> <span class=\"k\">in</span>\n     <span class=\"k\">return</span> <span class=\"s\">\"</span><span class=\"si\">\\(</span><span class=\"n\">key</span><span class=\"si\">)</span><span class=\"s\">=</span><span class=\"si\">\\(</span><span class=\"n\">value</span><span class=\"si\">)</span><span class=\"s\">\"</span>\n   <span class=\"p\">}</span>\n\n   <span class=\"k\">return</span> <span class=\"n\">parameterArray</span><span class=\"p\">.</span><span class=\"n\">joined</span><span class=\"p\">(</span><span class=\"n\">separator</span><span class=\"p\">:</span> <span class=\"s\">\"&amp;\"</span><span class=\"p\">)</span>\n <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Now you can use this to quickly and efficiently create a network request to the Product Hunt API.</p>"},{"id":"T0E6OlNlY3Rpb24tNzE5NA==","title":"Use EndPoints To Construct Request","htmlContent":"<p>Now we can clean up the code in <code>NetworkManager</code></p><div class=\"action\">\n<p>\nAdd a private method <code>makeRequest</code> to the <code>NetworkManager</code> class.</p>\n<pre><span class=\"c1\">// All the code we did before but cleaned up into their own methods</span>\n<span class=\"kd\">private</span> <span class=\"kd\">func</span> <span class=\"nf\">makeRequest</span><span class=\"p\">(</span><span class=\"k\">for</span> <span class=\"n\">endPoint</span><span class=\"p\">:</span> <span class=\"n\">EndPoints</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"n\">URLRequest</span> <span class=\"p\">{</span>\n  <span class=\"c1\">// grab the parameters from the endpoint and convert them into a string</span>\n  <span class=\"kd\">let</span> <span class=\"nv\">stringParams</span> <span class=\"p\">=</span> <span class=\"n\">endPoint</span><span class=\"p\">.</span><span class=\"n\">paramsToString</span><span class=\"p\">()</span>\n  <span class=\"c1\">// get the path of the endpoint</span>\n  <span class=\"kd\">let</span> <span class=\"nv\">path</span> <span class=\"p\">=</span> <span class=\"n\">endPoint</span><span class=\"p\">.</span><span class=\"n\">getPath</span><span class=\"p\">()</span>\n  <span class=\"c1\">// create the full url from the above variables</span>\n  <span class=\"kd\">let</span> <span class=\"nv\">fullURL</span> <span class=\"p\">=</span> <span class=\"n\">URL</span><span class=\"p\">(</span><span class=\"n\">string</span><span class=\"p\">:</span> <span class=\"n\">baseURL</span><span class=\"p\">.</span><span class=\"n\">appending</span><span class=\"p\">(</span><span class=\"s\">\"</span><span class=\"si\">\\(</span><span class=\"n\">path</span><span class=\"si\">)</span><span class=\"s\">?</span><span class=\"si\">\\(</span><span class=\"n\">stringParams</span><span class=\"si\">)</span><span class=\"s\">\"</span><span class=\"p\">))</span><span class=\"o\">!</span>\n  <span class=\"c1\">// build the request</span>\n  <span class=\"kd\">var</span> <span class=\"nv\">request</span> <span class=\"p\">=</span> <span class=\"n\">URLRequest</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">:</span> <span class=\"n\">fullURL</span><span class=\"p\">)</span>\n  <span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">httpMethod</span> <span class=\"p\">=</span> <span class=\"n\">endPoint</span><span class=\"p\">.</span><span class=\"n\">getHTTPMethod</span><span class=\"p\">()</span>\n  <span class=\"n\">request</span><span class=\"p\">.</span><span class=\"n\">allHTTPHeaderFields</span> <span class=\"p\">=</span> <span class=\"n\">endPoint</span><span class=\"p\">.</span><span class=\"n\">getHeaders</span><span class=\"p\">(</span><span class=\"n\">token</span><span class=\"p\">:</span> <span class=\"n\">token</span><span class=\"p\">)</span>\n\n  <span class=\"k\">return</span> <span class=\"n\">request</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>We'll also use an <code>enum</code> to create a <code>Result</code> type that allows us to easily handle different responses from the API.</p><div class=\"action\">\n<p>\nCreate an enum <code>Result</code> inside the <code>NetworkManager</code> class with <code>success</code> case for returning decoded data, and <code>failure</code> case for returning error messages from the response.</p>\n<pre><span class=\"kd\">enum</span> <span class=\"nc\">Result</span><span class=\"p\">&lt;</span><span class=\"n\">T</span><span class=\"p\">&gt;</span> <span class=\"p\">{</span>\n <span class=\"k\">case</span> <span class=\"n\">success</span><span class=\"p\">(</span><span class=\"n\">T</span><span class=\"p\">)</span>\n <span class=\"k\">case</span> <span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">Error</span><span class=\"p\">)</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p><strong>HOLD UP</strong> What is <code>&lt;T&gt;</code>? What is <code>&lt; &gt;</code> and what is this <code>T</code>?</p><p>The generic version of the function uses a placeholder type name (called <code>T</code> , in this case) instead of an actual type name (such as Int , String , or Double). The <code>&lt; &gt;</code> are what makes the class generic.</p><div class=\"info\">\n<p>\nGeneric code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.</p>\n\n<p>You can read more about generics <a href=\"https://docs.swift.org/swift-book/LanguageGuide/Generics.html\" target=\"_blank\">here</a></p>\n</div><p>And an <code>enum</code> to define all the errors we wish to handle in code.</p><div class=\"action\">\n<p>\nCreate an enum <code>EndPointError</code> and add this inside the <code>NetworkManager</code> class</p>\n<pre><span class=\"kd\">enum</span> <span class=\"nc\">EndPointError</span><span class=\"p\">:</span> <span class=\"n\">Error</span> <span class=\"p\">{</span>\n  <span class=\"k\">case</span> <span class=\"n\">couldNotParse</span>\n  <span class=\"k\">case</span> <span class=\"n\">noData</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE5NQ==","title":"Update Get Posts Method","htmlContent":"<p>Now we can update the <code>getPosts</code> method to use the enums we created to build requests and handle responses from the API.</p><div class=\"action\">\n<p>\nUpdate the <code>getPosts</code> method parameters to use the <code>Result</code> type.</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">getPosts</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">completion</span><span class=\"p\">:</span> <span class=\"p\">@</span><span class=\"n\">escaping</span> <span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"o\">&lt;</span><span class=\"p\">[</span><span class=\"n\">Post</span><span class=\"p\">]</span><span class=\"o\">&gt;</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n</pre>\n<p>Replace the body of the <code>getPosts</code> method to use the enums we created and reduce the redundancy that it currently has:</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">getPosts</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">completion</span><span class=\"p\">:</span> <span class=\"p\">@</span><span class=\"n\">escaping</span> <span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"o\">&lt;</span><span class=\"p\">[</span><span class=\"n\">Post</span><span class=\"p\">]</span><span class=\"o\">&gt;</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">postsRequest</span> <span class=\"p\">=</span> <span class=\"n\">makeRequest</span><span class=\"p\">(</span><span class=\"k\">for</span><span class=\"p\">:</span> <span class=\"p\">.</span><span class=\"n\">posts</span><span class=\"p\">)</span>\n   <span class=\"kd\">let</span> <span class=\"nv\">task</span> <span class=\"p\">=</span> <span class=\"n\">urlSession</span><span class=\"p\">.</span><span class=\"n\">dataTask</span><span class=\"p\">(</span><span class=\"n\">with</span><span class=\"p\">:</span> <span class=\"n\">postsRequest</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">error</span> <span class=\"k\">in</span>\n       <span class=\"c1\">// Check for errors.</span>\n       <span class=\"k\">if</span> <span class=\"kd\">let</span> <span class=\"nv\">error</span> <span class=\"p\">=</span> <span class=\"n\">error</span> <span class=\"p\">{</span>\n           <span class=\"k\">return</span> <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">))</span>\n       <span class=\"p\">}</span>\n\n       <span class=\"c1\">// Check to see if there is any data that was retrieved.</span>\n       <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">data</span> <span class=\"p\">=</span> <span class=\"n\">data</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n           <span class=\"k\">return</span> <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">EndPointError</span><span class=\"p\">.</span><span class=\"n\">noData</span><span class=\"p\">))</span>\n       <span class=\"p\">}</span>\n\n       <span class=\"c1\">// Attempt to decode the data.</span>\n       <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">result</span> <span class=\"p\">=</span> <span class=\"k\">try</span><span class=\"p\">?</span> <span class=\"n\">JSONDecoder</span><span class=\"p\">().</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"n\">PostList</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">from</span><span class=\"p\">:</span> <span class=\"n\">data</span><span class=\"p\">)</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n           <span class=\"k\">return</span> <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">EndPointError</span><span class=\"p\">.</span><span class=\"n\">couldNotParse</span><span class=\"p\">))</span>\n       <span class=\"p\">}</span>\n\n       <span class=\"kd\">let</span> <span class=\"nv\">posts</span> <span class=\"p\">=</span> <span class=\"n\">result</span><span class=\"p\">.</span><span class=\"n\">posts</span>\n\n       <span class=\"c1\">// Return the result with the completion handler.</span>\n       <span class=\"n\">DispatchQueue</span><span class=\"p\">.</span><span class=\"n\">main</span><span class=\"p\">.</span><span class=\"n\">async</span> <span class=\"p\">{</span>\n           <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"p\">.</span><span class=\"n\">success</span><span class=\"p\">(</span><span class=\"n\">posts</span><span class=\"p\">))</span>\n       <span class=\"p\">}</span>\n   <span class=\"p\">}</span>\n\n   <span class=\"n\">task</span><span class=\"p\">.</span><span class=\"n\">resume</span><span class=\"p\">()</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzE5Ng==","title":"Create Get Comments Method","htmlContent":"<p>Now it should be relatively easy to send a request to get a post's comments&gt; [action]</p><div class=\"action\">\n<p>\nCreate method to get comments for a post:</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">getComments</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">postId</span><span class=\"p\">:</span> <span class=\"nb\">Int</span><span class=\"p\">,</span> <span class=\"n\">completion</span><span class=\"p\">:</span> <span class=\"p\">@</span><span class=\"n\">escaping</span> <span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"o\">&lt;</span><span class=\"p\">[</span><span class=\"n\">Comment</span><span class=\"p\">]</span><span class=\"o\">&gt;</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"nb\">Void</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n  <span class=\"kd\">let</span> <span class=\"nv\">commentsRequest</span> <span class=\"p\">=</span> <span class=\"n\">makeRequest</span><span class=\"p\">(</span><span class=\"k\">for</span><span class=\"p\">:</span> <span class=\"p\">.</span><span class=\"n\">comments</span><span class=\"p\">(</span><span class=\"n\">postId</span><span class=\"p\">:</span> <span class=\"n\">postId</span><span class=\"p\">))</span>\n  <span class=\"kd\">let</span> <span class=\"nv\">task</span> <span class=\"p\">=</span> <span class=\"n\">urlSession</span><span class=\"p\">.</span><span class=\"n\">dataTask</span><span class=\"p\">(</span><span class=\"n\">with</span><span class=\"p\">:</span> <span class=\"n\">commentsRequest</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">data</span><span class=\"p\">,</span> <span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">error</span> <span class=\"k\">in</span>\n    <span class=\"c1\">// Check for errors</span>\n    <span class=\"k\">if</span> <span class=\"kd\">let</span> <span class=\"nv\">error</span> <span class=\"p\">=</span> <span class=\"n\">error</span> <span class=\"p\">{</span>\n      <span class=\"k\">return</span> <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">))</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// Check to see if there is any data that was retrieved.</span>\n    <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">data</span> <span class=\"p\">=</span> <span class=\"n\">data</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n      <span class=\"k\">return</span> <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">EndPointError</span><span class=\"p\">.</span><span class=\"n\">noData</span><span class=\"p\">))</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// Attempt to decode the comment data.</span>\n    <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">result</span> <span class=\"p\">=</span> <span class=\"k\">try</span><span class=\"p\">?</span> <span class=\"n\">JSONDecoder</span><span class=\"p\">().</span><span class=\"n\">decode</span><span class=\"p\">(</span><span class=\"n\">CommentApiResponse</span><span class=\"p\">.</span><span class=\"kc\">self</span><span class=\"p\">,</span> <span class=\"n\">from</span><span class=\"p\">:</span> <span class=\"n\">data</span><span class=\"p\">)</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n      <span class=\"k\">return</span> <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">EndPointError</span><span class=\"p\">.</span><span class=\"n\">couldNotParse</span><span class=\"p\">))</span>\n    <span class=\"p\">}</span>\n\n    <span class=\"c1\">// Return the result with the completion handler.</span>\n    <span class=\"n\">DispatchQueue</span><span class=\"p\">.</span><span class=\"n\">main</span><span class=\"p\">.</span><span class=\"n\">async</span> <span class=\"p\">{</span>\n      <span class=\"n\">completion</span><span class=\"p\">(</span><span class=\"n\">Result</span><span class=\"p\">.</span><span class=\"n\">success</span><span class=\"p\">(</span><span class=\"n\">result</span><span class=\"p\">.</span><span class=\"n\">comments</span><span class=\"p\">))</span>\n    <span class=\"p\">}</span>\n  <span class=\"p\">}</span>\n\n  <span class=\"n\">task</span><span class=\"p\">.</span><span class=\"n\">resume</span><span class=\"p\">()</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Well done! We got more practice here in <strong>decoding JSON into Swift models, building out our network layer, and working with an API!</strong></p><p>Unfortunately we have a problem: If we try to build right now, we'll get errors since we still need to update our view controllers to utilize what we've written in <code>NetworkManager</code>. Once we do that though, we'll have our very own Product Hunt Reader!</p>"},{"id":"T0E6OlNlY3Rpb24tNzE5Nw==","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Integrate comments API'</span>\n$ git push\n</pre>"}]},"next":{"id":"T0E6OlBhZ2UtMTYzOA==","slug":"update-view-controllers","title":"Updating View Controllers"},"previous":{"id":"T0E6OlBhZ2UtMTYzOA==","slug":"update-view-controllers","title":"Updating View Controllers"}},{"id":"T0E6OlBhZ2UtMTYzOA==","title":"Updating View Controllers","slug":"update-view-controllers","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzkwMA==","title":"Updating View Controllers","htmlContent":"<p>Now we have everything we need to have the full app working and ready to show to the client.</p><p>First let's update the <code>FeedViewController</code> to use the refactored networking methods.</p>"},{"id":"T0E6OlNlY3Rpb24tNzkwMQ==","title":"Update FeedViewController","htmlContent":"<div class=\"action\">\n<p>\nChange <code>updateFeed</code> method to use new <code>getPosts</code> method.</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">updateFeed</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n   <span class=\"n\">networkManager</span><span class=\"p\">.</span><span class=\"n\">getPosts</span><span class=\"p\">()</span> <span class=\"p\">{</span> <span class=\"n\">result</span> <span class=\"k\">in</span>\n       <span class=\"k\">switch</span> <span class=\"n\">result</span> <span class=\"p\">{</span>\n       <span class=\"k\">case</span> <span class=\"kd\">let</span> <span class=\"p\">.</span><span class=\"n\">success</span><span class=\"p\">(</span><span class=\"n\">posts</span><span class=\"p\">):</span>\n         <span class=\"kc\">self</span><span class=\"p\">.</span><span class=\"n\">posts</span> <span class=\"p\">=</span> <span class=\"n\">posts</span>\n       <span class=\"k\">case</span> <span class=\"kd\">let</span> <span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">):</span>\n         <span class=\"bp\">print</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">)</span>\n       <span class=\"p\">}</span>\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Instead of setting the <code>comments</code> list to mock data when pushing a <code>CommentsViewController</code> onto the <code>navigationController</code>, we'll send in the <strong>id</strong> of the post that was tapped.</p><div class=\"action\">\n<p>\nUpdate the <code>tableView(tableView: didSelectRowAt:)</code> in our <code>FeedViewController.swift</code></p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">didSelectRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n   <span class=\"p\">...</span>\n   <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">commentsView</span> <span class=\"p\">=</span> <span class=\"n\">storyboard</span><span class=\"p\">.</span><span class=\"n\">instantiateViewController</span><span class=\"p\">(</span><span class=\"n\">withIdentifier</span><span class=\"p\">:</span> <span class=\"s\">\"commentsView\"</span><span class=\"p\">)</span> <span class=\"k\">as</span><span class=\"p\">?</span> <span class=\"n\">CommentsViewController</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n     <span class=\"k\">return</span>\n   <span class=\"p\">}</span>\n   <span class=\"c1\">// set the post id for the comments</span>\n   <span class=\"n\">commentsView</span><span class=\"p\">.</span><span class=\"n\">postID</span> <span class=\"p\">=</span> <span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">id</span>\n   <span class=\"n\">navigationController</span><span class=\"p\">?.</span><span class=\"n\">pushViewController</span><span class=\"p\">(</span><span class=\"n\">commentsView</span><span class=\"p\">,</span> <span class=\"n\">animated</span><span class=\"p\">:</span> <span class=\"kc\">true</span><span class=\"p\">)</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzkwMg==","title":"Update CommentsViewController","htmlContent":"<div class=\"action\">\n<p>\nUpdate <code>comments</code> to fill in its <code>didSet</code> method, add a <code>postID</code>, and add a <code>NetworkManager</code>. Be sure to update the comment var to an array of Comments and not an array of Strings:</p>\n<pre><span class=\"kd\">class</span> <span class=\"nc\">CommentsViewController</span><span class=\"p\">:</span> <span class=\"bp\">UIViewController</span> <span class=\"p\">{</span>\n <span class=\"p\">...</span>\n\n<span class=\"kd\">var</span> <span class=\"nv\">comments</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"n\">Comment</span><span class=\"p\">]</span> <span class=\"p\">=</span> <span class=\"p\">[]</span> <span class=\"p\">{</span>\n    <span class=\"kr\">didSet</span> <span class=\"p\">{</span>\n        <span class=\"n\">commentsTableView</span><span class=\"p\">.</span><span class=\"n\">reloadData</span><span class=\"p\">()</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n <span class=\"kd\">var</span> <span class=\"nv\">postID</span><span class=\"p\">:</span> <span class=\"nb\">Int</span><span class=\"p\">!</span>\n\n <span class=\"kd\">var</span> <span class=\"nv\">networkManager</span> <span class=\"p\">=</span> <span class=\"n\">NetworkManager</span><span class=\"p\">()</span>\n\n<span class=\"p\">}</span>\n</pre>\n<p>Add a method to pull comments from <code>networkManager</code> called <code>updateComments</code></p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">updateComments</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n   <span class=\"c1\">// Similar to what we did for posts</span>\n   <span class=\"n\">networkManager</span><span class=\"p\">.</span><span class=\"n\">getComments</span><span class=\"p\">(</span><span class=\"n\">postID</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">result</span> <span class=\"k\">in</span>\n       <span class=\"k\">switch</span> <span class=\"n\">result</span> <span class=\"p\">{</span>\n       <span class=\"k\">case</span> <span class=\"kd\">let</span> <span class=\"p\">.</span><span class=\"n\">success</span><span class=\"p\">(</span><span class=\"n\">comments</span><span class=\"p\">):</span>\n         <span class=\"kc\">self</span><span class=\"p\">.</span><span class=\"n\">comments</span> <span class=\"p\">=</span> <span class=\"n\">comments</span>\n       <span class=\"k\">case</span> <span class=\"kd\">let</span> <span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">):</span>\n         <span class=\"bp\">print</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">)</span>\n       <span class=\"p\">}</span>\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n<p>Add the <code>updateComments()</code> method to the <code>CommentsViewController</code>'s <code>viewDidLoad()</code></p>\n<pre><span class=\"kr\">override</span> <span class=\"kd\">func</span> <span class=\"nf\">viewDidLoad</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n<span class=\"p\">...</span>\n\n   <span class=\"n\">updateComments</span><span class=\"p\">()</span>\n<span class=\"p\">}</span>\n</pre>\n<p>Update the <code>tableView(tableView: cellForRowAt:)</code> method to use the properties of our <code>Comment</code> model.</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">cellForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n   <span class=\"p\">...</span>\n\n   <span class=\"kd\">let</span> <span class=\"nv\">comment</span> <span class=\"p\">=</span> <span class=\"n\">comments</span><span class=\"p\">[</span><span class=\"n\">indexPath</span><span class=\"p\">.</span><span class=\"n\">row</span><span class=\"p\">]</span>\n   <span class=\"n\">cell</span><span class=\"p\">.</span><span class=\"n\">commentTextView</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"n\">comment</span><span class=\"p\">.</span><span class=\"n\">body</span>\n   <span class=\"k\">return</span> <span class=\"n\">cell</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzkwMw==","title":"Product So Far","htmlContent":"<p>Done! Now you have a completed product ready to show the client &#128516;</p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P12-Updating-View-Controllers/assets/01_Update-CommentsViewController_final-product.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P12-Updating-View-Controllers/assets/01_Update-CommentsViewController_final-product.png\" alt=\"Final Feed\" title=\"\">\n        </a></p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P12-Updating-View-Controllers/assets/02_Update-CommentsViewController_final-comments.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P12-Updating-View-Controllers/assets/02_Update-CommentsViewController_final-comments.png\" alt=\"Final Comments\" title=\"\">\n        </a></p><p>Congratulations! As you go through this MOB course, see how you can relate what you've learned here to the material in class!</p>"},{"id":"T0E6OlNlY3Rpb24tNzkwNA==","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Completed PH Reader'</span>\n$ git push\n</pre>"},{"id":"T0E6OlNlY3Rpb24tNzkwNQ==","title":"Feedback and Review - 2 minutes","htmlContent":"<p><strong>We promise this won't take longer than 2 minutes!</strong></p><p>Please take a moment to rate your understanding of learning outcomes from this tutorial, and how we can improve it via our <a href=\"https://goo.gl/forms/Lf2pJt1sjfJZF8VZ2\" target=\"_blank\">tutorial feedback form</a></p>"},{"id":"T0E6OlNlY3Rpb24tNzkwNg==","title":"Stretch Challenges","htmlContent":"<p>If you're still hungry for more, here are some stretch challenges to improve upon your product:</p><div class=\"challenge\">\n<p></p>\n\n<ul>\n<li>We still don't have images being pulled into the app! Replace the <code>placeholder</code> image with the actual images of the products from the Product Hunt API</li>\n<li>Allow users to filter by <code>topics</code> (check out the <code>post</code> data from the Product Hunt API)</li>\n<li>For each product, show the <code>maker</code> of that product by displaying their name and picture underneath the product <code>tagline</code> (Product Hunt API <code>post</code> data can help you here too!)</li>\n</ul>\n</div>"}]},"next":null,"previous":null}]}},"page":{"id":"T0E6OlBhZ2UtMTYzOA==","title":"Updating View Controllers","slug":"update-view-controllers","sections":{"nodes":[{"id":"T0E6OlNlY3Rpb24tNzkwMA==","title":"Updating View Controllers","htmlContent":"<p>Now we have everything we need to have the full app working and ready to show to the client.</p><p>First let's update the <code>FeedViewController</code> to use the refactored networking methods.</p>"},{"id":"T0E6OlNlY3Rpb24tNzkwMQ==","title":"Update FeedViewController","htmlContent":"<div class=\"action\">\n<p>\nChange <code>updateFeed</code> method to use new <code>getPosts</code> method.</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">updateFeed</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n   <span class=\"n\">networkManager</span><span class=\"p\">.</span><span class=\"n\">getPosts</span><span class=\"p\">()</span> <span class=\"p\">{</span> <span class=\"n\">result</span> <span class=\"k\">in</span>\n       <span class=\"k\">switch</span> <span class=\"n\">result</span> <span class=\"p\">{</span>\n       <span class=\"k\">case</span> <span class=\"kd\">let</span> <span class=\"p\">.</span><span class=\"n\">success</span><span class=\"p\">(</span><span class=\"n\">posts</span><span class=\"p\">):</span>\n         <span class=\"kc\">self</span><span class=\"p\">.</span><span class=\"n\">posts</span> <span class=\"p\">=</span> <span class=\"n\">posts</span>\n       <span class=\"k\">case</span> <span class=\"kd\">let</span> <span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">):</span>\n         <span class=\"bp\">print</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">)</span>\n       <span class=\"p\">}</span>\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n</div><p>Instead of setting the <code>comments</code> list to mock data when pushing a <code>CommentsViewController</code> onto the <code>navigationController</code>, we'll send in the <strong>id</strong> of the post that was tapped.</p><div class=\"action\">\n<p>\nUpdate the <code>tableView(tableView: didSelectRowAt:)</code> in our <code>FeedViewController.swift</code></p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">didSelectRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">{</span>\n   <span class=\"p\">...</span>\n   <span class=\"k\">guard</span> <span class=\"kd\">let</span> <span class=\"nv\">commentsView</span> <span class=\"p\">=</span> <span class=\"n\">storyboard</span><span class=\"p\">.</span><span class=\"n\">instantiateViewController</span><span class=\"p\">(</span><span class=\"n\">withIdentifier</span><span class=\"p\">:</span> <span class=\"s\">\"commentsView\"</span><span class=\"p\">)</span> <span class=\"k\">as</span><span class=\"p\">?</span> <span class=\"n\">CommentsViewController</span> <span class=\"k\">else</span> <span class=\"p\">{</span>\n     <span class=\"k\">return</span>\n   <span class=\"p\">}</span>\n   <span class=\"c1\">// set the post id for the comments</span>\n   <span class=\"n\">commentsView</span><span class=\"p\">.</span><span class=\"n\">postID</span> <span class=\"p\">=</span> <span class=\"n\">post</span><span class=\"p\">.</span><span class=\"n\">id</span>\n   <span class=\"n\">navigationController</span><span class=\"p\">?.</span><span class=\"n\">pushViewController</span><span class=\"p\">(</span><span class=\"n\">commentsView</span><span class=\"p\">,</span> <span class=\"n\">animated</span><span class=\"p\">:</span> <span class=\"kc\">true</span><span class=\"p\">)</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzkwMg==","title":"Update CommentsViewController","htmlContent":"<div class=\"action\">\n<p>\nUpdate <code>comments</code> to fill in its <code>didSet</code> method, add a <code>postID</code>, and add a <code>NetworkManager</code>. Be sure to update the comment var to an array of Comments and not an array of Strings:</p>\n<pre><span class=\"kd\">class</span> <span class=\"nc\">CommentsViewController</span><span class=\"p\">:</span> <span class=\"bp\">UIViewController</span> <span class=\"p\">{</span>\n <span class=\"p\">...</span>\n\n<span class=\"kd\">var</span> <span class=\"nv\">comments</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"n\">Comment</span><span class=\"p\">]</span> <span class=\"p\">=</span> <span class=\"p\">[]</span> <span class=\"p\">{</span>\n    <span class=\"kr\">didSet</span> <span class=\"p\">{</span>\n        <span class=\"n\">commentsTableView</span><span class=\"p\">.</span><span class=\"n\">reloadData</span><span class=\"p\">()</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n\n <span class=\"kd\">var</span> <span class=\"nv\">postID</span><span class=\"p\">:</span> <span class=\"nb\">Int</span><span class=\"p\">!</span>\n\n <span class=\"kd\">var</span> <span class=\"nv\">networkManager</span> <span class=\"p\">=</span> <span class=\"n\">NetworkManager</span><span class=\"p\">()</span>\n\n<span class=\"p\">}</span>\n</pre>\n<p>Add a method to pull comments from <code>networkManager</code> called <code>updateComments</code></p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">updateComments</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n   <span class=\"c1\">// Similar to what we did for posts</span>\n   <span class=\"n\">networkManager</span><span class=\"p\">.</span><span class=\"n\">getComments</span><span class=\"p\">(</span><span class=\"n\">postID</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"n\">result</span> <span class=\"k\">in</span>\n       <span class=\"k\">switch</span> <span class=\"n\">result</span> <span class=\"p\">{</span>\n       <span class=\"k\">case</span> <span class=\"kd\">let</span> <span class=\"p\">.</span><span class=\"n\">success</span><span class=\"p\">(</span><span class=\"n\">comments</span><span class=\"p\">):</span>\n         <span class=\"kc\">self</span><span class=\"p\">.</span><span class=\"n\">comments</span> <span class=\"p\">=</span> <span class=\"n\">comments</span>\n       <span class=\"k\">case</span> <span class=\"kd\">let</span> <span class=\"p\">.</span><span class=\"n\">failure</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">):</span>\n         <span class=\"bp\">print</span><span class=\"p\">(</span><span class=\"n\">error</span><span class=\"p\">)</span>\n       <span class=\"p\">}</span>\n   <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre>\n<p>Add the <code>updateComments()</code> method to the <code>CommentsViewController</code>'s <code>viewDidLoad()</code></p>\n<pre><span class=\"kr\">override</span> <span class=\"kd\">func</span> <span class=\"nf\">viewDidLoad</span><span class=\"p\">()</span> <span class=\"p\">{</span>\n<span class=\"p\">...</span>\n\n   <span class=\"n\">updateComments</span><span class=\"p\">()</span>\n<span class=\"p\">}</span>\n</pre>\n<p>Update the <code>tableView(tableView: cellForRowAt:)</code> method to use the properties of our <code>Comment</code> model.</p>\n<pre><span class=\"kd\">func</span> <span class=\"nf\">tableView</span><span class=\"p\">(</span><span class=\"kc\">_</span> <span class=\"n\">tableView</span><span class=\"p\">:</span> <span class=\"bp\">UITableView</span><span class=\"p\">,</span> <span class=\"n\">cellForRowAt</span> <span class=\"n\">indexPath</span><span class=\"p\">:</span> <span class=\"n\">IndexPath</span><span class=\"p\">)</span> <span class=\"p\">-&gt;</span> <span class=\"bp\">UITableViewCell</span> <span class=\"p\">{</span>\n   <span class=\"p\">...</span>\n\n   <span class=\"kd\">let</span> <span class=\"nv\">comment</span> <span class=\"p\">=</span> <span class=\"n\">comments</span><span class=\"p\">[</span><span class=\"n\">indexPath</span><span class=\"p\">.</span><span class=\"n\">row</span><span class=\"p\">]</span>\n   <span class=\"n\">cell</span><span class=\"p\">.</span><span class=\"n\">commentTextView</span><span class=\"p\">.</span><span class=\"n\">text</span> <span class=\"p\">=</span> <span class=\"n\">comment</span><span class=\"p\">.</span><span class=\"n\">body</span>\n   <span class=\"k\">return</span> <span class=\"n\">cell</span>\n<span class=\"p\">}</span>\n</pre>\n</div>"},{"id":"T0E6OlNlY3Rpb24tNzkwMw==","title":"Product So Far","htmlContent":"<p>Done! Now you have a completed product ready to show the client &#128516;</p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P12-Updating-View-Controllers/assets/01_Update-CommentsViewController_final-product.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P12-Updating-View-Controllers/assets/01_Update-CommentsViewController_final-product.png\" alt=\"Final Feed\" title=\"\">\n        </a></p><p><a href=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P12-Updating-View-Controllers/assets/02_Update-CommentsViewController_final-comments.png\" target=\"_blank\">\n          <img src=\"https://cdn.jsdelivr.net/gh/MakeSchool-Tutorials/Product-Hunt-API-Tutorial@064357932b51be51fd4b3dac68cd610ba71e0c2b/P12-Updating-View-Controllers/assets/02_Update-CommentsViewController_final-comments.png\" alt=\"Final Comments\" title=\"\">\n        </a></p><p>Congratulations! As you go through this MOB course, see how you can relate what you've learned here to the material in class!</p>"},{"id":"T0E6OlNlY3Rpb24tNzkwNA==","title":"Now Commit","htmlContent":"<pre>$ git add .\n$ git commit -m <span class=\"s1\">'Completed PH Reader'</span>\n$ git push\n</pre>"},{"id":"T0E6OlNlY3Rpb24tNzkwNQ==","title":"Feedback and Review - 2 minutes","htmlContent":"<p><strong>We promise this won't take longer than 2 minutes!</strong></p><p>Please take a moment to rate your understanding of learning outcomes from this tutorial, and how we can improve it via our <a href=\"https://goo.gl/forms/Lf2pJt1sjfJZF8VZ2\" target=\"_blank\">tutorial feedback form</a></p>"},{"id":"T0E6OlNlY3Rpb24tNzkwNg==","title":"Stretch Challenges","htmlContent":"<p>If you're still hungry for more, here are some stretch challenges to improve upon your product:</p><div class=\"challenge\">\n<p></p>\n\n<ul>\n<li>We still don't have images being pulled into the app! Replace the <code>placeholder</code> image with the actual images of the products from the Product Hunt API</li>\n<li>Allow users to filter by <code>topics</code> (check out the <code>post</code> data from the Product Hunt API)</li>\n<li>For each product, show the <code>maker</code> of that product by displaying their name and picture underneath the product <code>tagline</code> (Product Hunt API <code>post</code> data can help you here too!)</li>\n</ul>\n</div>"}]},"next":null,"previous":null}}},"staticQueryHashes":[]}