{"id":588,"date":"2014-06-02T18:39:22","date_gmt":"2014-06-03T00:39:22","guid":{"rendered":"http:\/\/jamesonquave.com\/blog\/?p=588"},"modified":"2017-04-17T15:57:20","modified_gmt":"2017-04-17T21:57:20","slug":"developing-ios-apps-using-swift-tutorial-part-2","status":"publish","type":"post","link":"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/","title":{"rendered":"Developing iOS Apps Using Swift Tutorial Part 2"},"content":{"rendered":"<p><strong>This section completely updated to reflect changes in Xcode 8.3.1, as of April 17, 2017<\/strong><\/p>\n<p>In part 1 we went over some basics of Swift, and set up a simple example project that creates a Table View and a puts some text inside of them. If you haven\u2019t read that yet, <a href=\"http:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial\/\">give it a read here<\/a>.<\/p>\n<p>For this section, we\u2019re going to do something a little more ambitious. We\u2019re going to hit the iTunes Search API for the iTunes Store, download the JSON results, parse them in to Dictionaries and then populate our Table View with this information. Then, we will add some user interaction by adding a click event to the tableview, so that when an item is clicked the iTunes store item will be opened.<\/p>\n<p>If this sounds like a lot of work, don\u2019t sweat it. This is pretty basic functionality for iOS apps and it\u2019s one of the most common things any developer has to do. Let\u2019s get going\u2026<\/p>\n<h2 id=\"connecting-the-ui\">Connecting the UI<\/h2>\n<p>The first thing we need to do is get a reference to our tableView, so it can be used from code. Go ahead and add this line to your ViewController.swift file, just under the class definition, but outside of any functions.<\/p>\n<pre><code><div id=\"highlighter_156532\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"keyword\">@IBOutlet<\/code> <code class=\"keyword\">var<\/code> <code class=\"plain\">appsTableView : <\/code><code class=\"color2\">UITableView<\/code><code class=\"plain\">!<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>This bit of code allows up to connect our Table View in our Storyboard to this variable, \u201cappsTableView\u201d. Save this file and open up your storyboard. Now select the View Controller object (the one with a yellow icon) and in the right-hand side pane click the last tab, the Connections Inspector. Here you should now see an outlet for \u201cappsTableView\u201d. Click and drag from the dot next to this outlet on to the Table View in our scene.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i1.wp.com\/jamesonquave.com\/tutImg\/ConnectTableView.png?w=584\" alt=\"Connecting the Table View to the View Controller\"><\/p>\n<p>Let\u2019s also add a variable to hold the table data itself. Just under the class definition for ViewController add:<\/p>\n<pre><code><div id=\"highlighter_424531\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"keyword\">var<\/code> <code class=\"plain\">tableData = [[<\/code><code class=\"color1\">String<\/code><code class=\"plain\">: <\/code><code class=\"color1\">String<\/code><code class=\"plain\">]]()<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>This variable is an <code>Array<\/code> type that contains multiple  <code>Dictionary<\/code> types (or hashable types if you prefer). Inside these values the key is of type <code>String<\/code> as well as the value. Or in other words I can get or set <code>String<\/code> values by accessing this variable with any <code>String<\/code> key in the dictionary, as we&#8217;ll see in a moment. If that does&#8217;t make sense just yet, just keep going and you&#8217;ll see how it&#8217;s used later in the tutorial.<\/p>\n<h2 id=\"making-the-api-request\">Making the API Request<\/h2>\n<p>Now that we have the UI connected, we\u2019re ready to make an API call. Create a new function called searchItunesFor(searchTerm: String). We\u2019ll use this to make our requests happen for arbitrary search terms.<\/p>\n<p>To keep this tutorial short, I\u2019m going to just post my final code and let the comments do some of the explaining. I&#8217;ll also break it down line-by-line afterward. Also, I\u2019m always open to questions and further discussion in the comments though, so feel free to chime in!<\/p>\n<pre><code><div id=\"highlighter_81159\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"keyword\">func<\/code> <code class=\"plain\">searchItunes(searchTerm: <\/code><code class=\"color2\">String<\/code><code class=\"plain\">) {<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">itunesSearchTerm = searchTerm.replacingOccurrences(of: <\/code><code class=\"string\">\" \"<\/code><code class=\"plain\">, with: <\/code><code class=\"string\">\"+\"<\/code><code class=\"plain\">, options: .caseInsensitive, range: <\/code><code class=\"keyword\">nil<\/code><code class=\"plain\">)<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Also replace every character with a percent encoding<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">escapedSearchTerm = itunesSearchTerm.addingPercentEncoding(withAllowedCharacters: [])!<\/code><\/div><div class=\"line number6 index5 alt1\">&nbsp;<\/div><div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ This is the URL that Apple offers for their search API<\/code><\/div><div class=\"line number8 index7 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">urlString = <\/code><code class=\"string\">\"<a href=\"http:\/\/itunes.apple.com\/search?term=\">http:\/\/itunes.apple.com\/search?term=<\/a>\\(escapedSearchTerm)&amp;media=software\"<\/code><\/div><div class=\"line number9 index8 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">url = <\/code><code class=\"color2\">URL<\/code><code class=\"plain\">(string: urlString)!<\/code><\/div><div class=\"line number10 index9 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"color2\">URLSession<\/code><code class=\"plain\">.shared.dataTask(with: url) { (data, response, error) <\/code><code class=\"keyword\">in<\/code><\/div><div class=\"line number11 index10 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">if<\/code> <code class=\"keyword\">let<\/code> <code class=\"plain\">error = error {<\/code><\/div><div class=\"line number12 index11 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ If there is an error in the web request, print it to the console<\/code><\/div><div class=\"line number13 index12 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"functions\">print<\/code><code class=\"plain\">(error)<\/code><\/div><div class=\"line number14 index13 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">return<\/code><\/div><div class=\"line number15 index14 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">}<\/code><\/div><div class=\"line number16 index15 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Because we'll be calling a function that can throw an error<\/code><\/div><div class=\"line number17 index16 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ we need to wrap the attempt inside of a do { } block<\/code><\/div><div class=\"line number18 index17 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ and catch any error that comes back inside the catch block<\/code><\/div><div class=\"line number19 index18 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">do {<\/code><\/div><div class=\"line number20 index19 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">jsonResult = try <\/code><code class=\"color2\">JSONSerialization<\/code><code class=\"plain\">.jsonObject(with: data!, options: []) <\/code><code class=\"keyword\">as<\/code><code class=\"plain\">! [<\/code><code class=\"color2\">String<\/code><code class=\"plain\">: <\/code><code class=\"color2\">Any<\/code><code class=\"plain\">]<\/code><\/div><div class=\"line number21 index20 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">self<\/code><code class=\"plain\">.didReceive(searchResult: jsonResult)<\/code><\/div><div class=\"line number22 index21 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">}<\/code><\/div><div class=\"line number23 index22 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">catch <\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">err {<\/code><\/div><div class=\"line number24 index23 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"functions\">print<\/code><code class=\"plain\">(err.localizedDescription)<\/code><\/div><div class=\"line number25 index24 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">}<\/code><\/div><div class=\"line number26 index25 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Close the dataTask block, and call resume() in order to make it run immediately<\/code><\/div><div class=\"line number27 index26 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">}.resume()<\/code><\/div><div class=\"line number28 index27 alt1\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>First, we fix some issues with the search terms. For one thing, the iTunes API is not going to like seing spaces, instead it wants plus signs (+), so the replacingOccurences function does this work, and we put the result in the itunesSearchTerm variable.<\/p>\n<p>Next, we also want to make sure no other characters will cause issues. For example a question mark (?) may be viewed by the API as the end of the request if it was included in the search term. So we use the method <code>addingPercentEncoding<\/code> to encoded every character in to a percent-encoded form, and store this new value in to escapedSearchTerm.<\/p>\n<p>After that we define our URL, which is just the iTunes search API URL with the <code>escapedSearchTerm<\/code> inserted in to the <code>term<\/code> field. We store this in the variable <code>urlString<\/code>. Next, we convert this URL <code>String<\/code> in to a proper <code>URL<\/code> object. This will basically validate that the URL is valid, or at least properly-formed, and then it gives it some useful methods as well that are common to URLs.<\/p>\n<p>Now comes the network request. We make the request from the <code>URLSession<\/code> API that Apple provides. You could create a <code>URLSession<\/code> for this task, but Apple&#8217;s API will provide a pre-constructed one called <code>shared<\/code>. We access this with the simple dot-notation <code>URLSession.shared<\/code>.<\/p>\n<p>From here, we use the shared sesion to create a new Data Task by calling it&#8217;s <code>dataTask<\/code> function with the <code>url<\/code> we created the line before. The next part is the completion handler. This itself is a function we define inline, inside of the curly braces.<\/p>\n<p>So, everything here inside of the curly braces, where the indentation is increased, is only executed after the Data Task has been completed. Hopefully when this happens, what we get back from the server is JSON data containing the search results! It&#8217;s also possible that there was some kind of error, so we check whether or not an error is present by using the optional binding syntax:<\/p>\n<pre><code><div id=\"highlighter_540477\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"keyword\">if<\/code> <code class=\"keyword\">let<\/code> <code class=\"plain\">error = error {<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"plain\">...<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>This syntax replaces the optional <code>error: Error?<\/code> with an unwrapped optional <code>error: Error<\/code>, but only if it exists. Most of the time, the value of <code>error<\/code> will be <code>nil<\/code>, and this block of code will be skipped entirely.<\/p>\n<p>Next we are going to decode the result from a <code>Data<\/code> object in to a dictionary we can use to access each JSON element in the results.<\/p>\n<p>Because the Apple APIs for JSON deserialization can <code>throw<\/code> an error, we perform this work inside of a <code>do { }<\/code> block, with a <code>catch let err<\/code> block after it. If something goes wrong during JSON deserialization, the <code>catch<\/code> block will be executed. But if everything goes to plan, the <code>do<\/code> block will complete executing.<\/p>\n<p>Once we get the deserialized data back, we call a new method <code>self.didReceive(searchResult: jsonResult)<\/code>.<br \/>\nThis method is not defined yet, so we&#8217;ll define it next.<\/p>\n<p>Finally we call <code>resume()<\/code> at the end of the dataTask block in order to execute the API request immediately.<\/p>\n<h3 id=\"getting-the-data-we-need-out-of-the-json-response\">Getting the data we need out of the JSON response<\/h3>\n<p>Now that we are getting a JSON response back, we will want to take out the values we care about. In this case that&#8217;s the price, a thumbnail, and the name of the app. So next, let&#8217;s create the <code>didReceive<\/code> method inside our ViewController class in order to parse out this data and store it inside the <code>tableData<\/code> variable that will inform our Table View.<\/p>\n<pre><code><div id=\"highlighter_468536\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"keyword\">func<\/code> <code class=\"plain\">didReceive(searchResult: [<\/code><code class=\"color1\">String<\/code><code class=\"plain\">: <\/code><code class=\"color2\">Any<\/code><code class=\"plain\">]) {<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Make sure the results are in the expected format of [String: Any]<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">guard <\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">results = searchResult[<\/code><code class=\"string\">\"results\"<\/code><code class=\"plain\">] <\/code><code class=\"keyword\">as<\/code><code class=\"plain\">? [[<\/code><code class=\"color1\">String<\/code><code class=\"plain\">: <\/code><code class=\"color2\">Any<\/code><code class=\"plain\">]] <\/code><code class=\"keyword\">else<\/code> <code class=\"plain\">{<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"functions\">print<\/code><code class=\"plain\">(<\/code><code class=\"string\">\"Could not process search results...\"<\/code><code class=\"plain\">)<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">return<\/code><\/div><div class=\"line number6 index5 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">}<\/code><\/div><div class=\"line number7 index6 alt2\">&nbsp;<\/div><div class=\"line number8 index7 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Create a temporary place to add the new list of app details to<\/code><\/div><div class=\"line number9 index8 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">var<\/code> <code class=\"plain\">apps = [[<\/code><code class=\"color2\">String<\/code><code class=\"plain\">: <\/code><code class=\"color1\">String<\/code><code class=\"plain\">]]()<\/code><\/div><div class=\"line number10 index9 alt1\">&nbsp;<\/div><div class=\"line number11 index10 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Loop through all the results...<\/code><\/div><div class=\"line number12 index11 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">for<\/code> <code class=\"plain\">result <\/code><code class=\"keyword\">in<\/code> <code class=\"plain\">results {<\/code><\/div><div class=\"line number13 index12 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Check that we have String values for each key we care about<\/code><\/div><div class=\"line number14 index13 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">if<\/code> <code class=\"keyword\">let<\/code> <code class=\"plain\">thumbnailURLString = result[<\/code><code class=\"string\">\"artworkUrl100\"<\/code><code class=\"plain\">] <\/code><code class=\"keyword\">as<\/code><code class=\"plain\">? <\/code><code class=\"color2\">String<\/code><code class=\"plain\">,<\/code><\/div><div class=\"line number15 index14 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">appName = result[<\/code><code class=\"string\">\"trackName\"<\/code><code class=\"plain\">] <\/code><code class=\"keyword\">as<\/code><code class=\"plain\">? <\/code><code class=\"color2\">String<\/code><code class=\"plain\">,<\/code><\/div><div class=\"line number16 index15 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">price = result[<\/code><code class=\"string\">\"formattedPrice\"<\/code><code class=\"plain\">] <\/code><code class=\"keyword\">as<\/code><code class=\"plain\">? <\/code><code class=\"color2\">String<\/code> <code class=\"plain\">{<\/code><\/div><div class=\"line number17 index16 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ All three data points are valid, add the record to the list<\/code><\/div><div class=\"line number18 index17 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">apps.append(<\/code><\/div><div class=\"line number19 index18 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">[<\/code><\/div><div class=\"line number20 index19 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"string\">\"thumbnailURLString\"<\/code><code class=\"plain\">: thumbnailURLString,<\/code><\/div><div class=\"line number21 index20 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"string\">\"appName\"<\/code><code class=\"plain\">: appName,<\/code><\/div><div class=\"line number22 index21 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"string\">\"price\"<\/code><code class=\"plain\">: price<\/code><\/div><div class=\"line number23 index22 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">]<\/code><\/div><div class=\"line number24 index23 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">)<\/code><\/div><div class=\"line number25 index24 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">}<\/code><\/div><div class=\"line number26 index25 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">}<\/code><\/div><div class=\"line number27 index26 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Update our tableData variable as a way to store<\/code><\/div><div class=\"line number28 index27 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ the list of app's data we pulled out of the JSON<\/code><\/div><div class=\"line number29 index28 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">tableData = apps<\/code><\/div><div class=\"line number30 index29 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Refresh the table with the new data<\/code><\/div><div class=\"line number31 index30 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"color2\">DispatchQueue<\/code><code class=\"plain\">.main.async {<\/code><\/div><div class=\"line number32 index31 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">self<\/code><code class=\"plain\">.appsTableView.reloadData()<\/code><\/div><div class=\"line number33 index32 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">}<\/code><\/div><div class=\"line number34 index33 alt1\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>Here we are first off checking that we have the right data type. The <code>results<\/code> argument passed in to the <code>didReceive<\/code> function here is our JSON value returned from the iTunes Search API. We are going to want to check for three keys:<\/p>\n<ul>\n<li>artworkUrl100<\/li>\n<li>trackName<\/li>\n<li>formattedPrice<\/li>\n<\/ul>\n<p>Why these keys? This is just the keys Apple chose in their API docs. If you take a look at a sample API response you&#8217;ll see keys contain the info we want about an app. <\/p>\n<p>So what we do is we loop through everything inside of the array of results, and then check that each of these three values are present, and are convertible to a <code>String<\/code> type. Here we&#8217;re using a compound form of the optional binding syntax that allows us to check for the valid presence of multiple values. <code>if let varA = valueA, let varB = valueB { }<\/code>. Not only are we checking for their presence, but if they can be represented as <code>String<\/code> objects.<\/p>\n<p>If all three keys are present, and they can all be represented as strings, then we have an app record! We&#8217;ll add it to the list of apps, a temporary variable we created to store each new app we come across for this query.<\/p>\n<p>I&#8217;m using slightly different keys for our app&#8217;s purposes. This is mainly just to show there is no reason these keys <strong>must<\/strong> match.<\/p>\n<p>Finally, once the list of <code>apps<\/code> is completely updated, we assign the <code>tableData<\/code> variable that is going to be used to hold the Table View&#8217;s data to the array of <code>apps<\/code> we just created. From there, we call <code>reloadData()<\/code> on the <code>appsTableView<\/code>, which let&#8217;s the table know there is new data to work with, and that it should re-render itself.<\/p>\n<p>You&#8217;ll notice the <code>reloadData()<\/code> is inside of another block. This one is from the Grand Central Dispatch API. By putting this code inside of the block <code>DispatchQueue.main.async { }<\/code>, we&#8217;re able to assure this is executed on the foreground thread. Because this code is all being executed in response to a network request (the API call), we end up on a background thread. This is because we know we have to wait a moment for the API to respond. The iOS App won&#8217;t just freeze the app up while it waits for the response. Instead, it will send the response in to a background thread.<\/p>\n<p>So, now that we are actually updating some UI, we want to jump back on to the main thread and make sure it shows up immediately. If you are curious, you can call <code>reloadData<\/code> outside of this block and see how it effects the performance of the app (after we update the actual UI in the next step)<\/p>\n<h3 id=\"update-the-ui-with-the-new-data\">Update the UI with the new data<\/h3>\n<p>Now that we&#8217;ve got our API call updating the <code>tableData<\/code> variable, and calling <code>reloadData()<\/code> on the <code>appsTableView<\/code> we connected earlier, we can proceed to actually implement those <code>UITableViewDataSource<\/code> methods we set up in the beginning of the tutorial&#8230;<\/p>\n<p>You may remember from last time we implemented the function for our Table View that we had a count method, which determines the number of rows; and a cell method, which actually creates the cell and modifies it for each row.<\/p>\n<p>We\u2019re going to update these now to use the data we pulled down from the web.<\/p>\n<p>Swap out your methods with these two functions:<\/p>\n<pre><code><div id=\"highlighter_638838\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"comments\">\/\/ MARK: UITableViewDataSource<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"keyword\">func<\/code> <code class=\"plain\">tableView(_ tableView: <\/code><code class=\"color2\">UITableView<\/code><code class=\"plain\">, numberOfRowsInSection section: <\/code><code class=\"color1\">Int<\/code><code class=\"plain\">) -&gt; <\/code><code class=\"color2\">Int<\/code> <code class=\"plain\">{<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">return<\/code> <code class=\"plain\">tableData.count<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"plain\">}<\/code><\/div><div class=\"line number5 index4 alt2\">&nbsp;<\/div><div class=\"line number6 index5 alt1\"><code class=\"keyword\">func<\/code> <code class=\"plain\">tableView(_ tableView: <\/code><code class=\"color1\">UITableView<\/code><code class=\"plain\">, cellForRowAt indexPath: <\/code><code class=\"color2\">IndexPath<\/code><code class=\"plain\">) -&gt; <\/code><code class=\"color1\">UITableViewCell<\/code> <code class=\"plain\">{<\/code><\/div><div class=\"line number7 index6 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">cell = <\/code><code class=\"color1\">UITableViewCell<\/code><code class=\"plain\">(style: .subtitle, reuseIdentifier: <\/code><code class=\"string\">\"MyTestCell\"<\/code><code class=\"plain\">)<\/code><\/div><div class=\"line number8 index7 alt1\">&nbsp;<\/div><div class=\"line number9 index8 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Get the app from the list at this row's index<\/code><\/div><div class=\"line number10 index9 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">let<\/code> <code class=\"plain\">app = tableData[indexPath.row]<\/code><\/div><div class=\"line number11 index10 alt2\">&nbsp;<\/div><div class=\"line number12 index11 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Pull out the relevant strings in the app record<\/code><\/div><div class=\"line number13 index12 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">cell.textLabel?.text = app[<\/code><code class=\"string\">\"appName\"<\/code><code class=\"plain\">]<\/code><\/div><div class=\"line number14 index13 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">cell.detailTextLabel?.text = app[<\/code><code class=\"string\">\"price\"<\/code><code class=\"plain\">]<\/code><\/div><div class=\"line number15 index14 alt2\">&nbsp;<\/div><div class=\"line number16 index15 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">return<\/code> <code class=\"plain\">cell<\/code><\/div><div class=\"line number17 index16 alt2\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>The first one is pretty simple. The number of rows should be the same as the count of the records in <code>tableData<\/code> (the number of app returned from the API).<\/p>\n<p>The second function is what creates the cell, which is what is displayed in the Table View. First we call the constructor to make a fresh <code>UITableViewCell<\/code> to work with. Then we retrieve the current <code>app<\/code> that should be displayed by accessing <code>tableData[indexPath.row]<\/code>. The variable <code>indexPath<\/code> is passed in as an argument by Apple&#8217;s Table View class. It represents the current index that it is asking for a cell for. It&#8217;s kind of a backwards way of thinking about it, but basically this function is the table itself asking for an individual row. Which row? Well&#8230; the one at <code>indexPath.row<\/code>.<\/p>\n<p>Next, we&#8217;ll set the text values for the text and detail labels of the cell. We&#8217;ll set these to be the value of the <code>app<\/code> array we created earlier in response to the API response.<\/p>\n<h3 id=\"call-the-api\">Call the API<\/h3>\n<p>As a final step, we&#8217;ll manually make the API call for our <code>searchItunes<\/code> method by adding it inside of the <code>viewDidLoad<\/code> function. The <code>viewDidLoad<\/code> method is called on this View Controller object any time the screen it represents is being constructed. This is a common pattern in iOS development.<\/p>\n<p>Find your <code>viewDidLoad<\/code> function (the Xcode template will have already added it) and add a call to the <code>searchItunes<\/code> function.<\/p>\n<pre><code><div id=\"highlighter_427375\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"keyword\">override<\/code> <code class=\"keyword\">func<\/code> <code class=\"plain\">viewDidLoad() {<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">super<\/code><code class=\"plain\">.viewDidLoad()<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Do any additional setup after loading the view, typically from a nib.<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">searchItunes(searchTerm: <\/code><code class=\"string\">\"JQ Software\"<\/code><code class=\"plain\">)<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<h3 id=\"it-s-alive-\">It&#8217;s alive!<\/h3>\n<p>Finally, run the app! Do you see the search results? You should see a few of my apps from the App Store pop up if you used my JQ Software search term. Try some other search terms and rebuild the app to see the different results that come back. You&#8217;ll notice we don&#8217;t yet have images in place, but we&#8217;ll get to that in later sections. We did get the data for that already after all.<\/p>\n<p>If you run the App using JQ Software as a search term it will look like this at this stage:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/p2sssm.png\" alt=\"JQ Software Apps List\"><\/p>\n<p>Next time in <a href=\"http:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-part-3-best-practices\/\">Part 3<\/a> we\u2019ll work on the interaction piece of the app, allowing users to search for anything they like, and making the table cells clickable!<\/p>\n<p><a href=\"https:\/\/github.com\/jquave\/Swift-Tutorial\/tree\/Part2\"><img decoding=\"async\" src=\"http:\/\/i0.wp.com\/jamesonquave.com\/images\/getTheSource.png?w=584\" alt=\"Download the Source Code\"><\/a><\/p>\n<p><a href=\"http:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-part-3-best-practices\/\"><img decoding=\"async\" src=\"http:\/\/i1.wp.com\/jamesonquave.com\/images\/nextPart.png?w=584\" alt=\"Go to the Next Part\"><\/a><\/p>\n<p><a href=\"http:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-part-3-best-practices\/\">Go to Part 3 now -&gt;<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This section completely updated to reflect changes in Xcode 8.3.1, as of April 17, 2017 In part 1 we went over some basics of Swift, and set up a simple example project that creates a Table View and a puts some text inside of them. If you haven\u2019t read that yet, give it a read&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_links_to":"","_links_to_target":""},"categories":[26,21,10,32],"tags":[37,15,38,14,33,36],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.13 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Developing iOS Apps Using Swift Tutorial Part 2 - Jameson Quave<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Developing iOS Apps Using Swift Tutorial Part 2 - Jameson Quave\" \/>\n<meta property=\"og:description\" content=\"This section completely updated to reflect changes in Xcode 8.3.1, as of April 17, 2017 In part 1 we went over some basics of Swift, and set up a simple example project that creates a Table View and a puts some text inside of them. If you haven\u2019t read that yet, give it a read...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/\" \/>\n<meta property=\"og:site_name\" content=\"Jameson Quave\" \/>\n<meta property=\"article:published_time\" content=\"2014-06-03T00:39:22+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-04-17T21:57:20+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/i1.wp.com\/jamesonquave.com\/tutImg\/ConnectTableView.png?w=584\" \/>\n<meta name=\"author\" content=\"Jameson Quave\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jameson Quave\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/\",\"url\":\"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/\",\"name\":\"Developing iOS Apps Using Swift Tutorial Part 2 - Jameson Quave\",\"isPartOf\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/#website\"},\"datePublished\":\"2014-06-03T00:39:22+00:00\",\"dateModified\":\"2017-04-17T21:57:20+00:00\",\"author\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc\"},\"breadcrumb\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/jamesonquave.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Developing iOS Apps Using Swift Tutorial Part 2\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#website\",\"url\":\"https:\/\/jamesonquave.com\/blog\/\",\"name\":\"Jameson Quave\",\"description\":\"Using computer technology to educate, and improve lives.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/jamesonquave.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc\",\"name\":\"Jameson Quave\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg\",\"caption\":\"Jameson Quave\"},\"sameAs\":[\"http:\/\/jamesonquave.com\"],\"url\":\"https:\/\/jamesonquave.com\/blog\/author\/jquave\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Developing iOS Apps Using Swift Tutorial Part 2 - Jameson Quave","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/","og_locale":"en_US","og_type":"article","og_title":"Developing iOS Apps Using Swift Tutorial Part 2 - Jameson Quave","og_description":"This section completely updated to reflect changes in Xcode 8.3.1, as of April 17, 2017 In part 1 we went over some basics of Swift, and set up a simple example project that creates a Table View and a puts some text inside of them. If you haven\u2019t read that yet, give it a read...","og_url":"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/","og_site_name":"Jameson Quave","article_published_time":"2014-06-03T00:39:22+00:00","article_modified_time":"2017-04-17T21:57:20+00:00","og_image":[{"url":"http:\/\/i1.wp.com\/jamesonquave.com\/tutImg\/ConnectTableView.png?w=584"}],"author":"Jameson Quave","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Jameson Quave","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/","url":"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/","name":"Developing iOS Apps Using Swift Tutorial Part 2 - Jameson Quave","isPartOf":{"@id":"https:\/\/jamesonquave.com\/blog\/#website"},"datePublished":"2014-06-03T00:39:22+00:00","dateModified":"2017-04-17T21:57:20+00:00","author":{"@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc"},"breadcrumb":{"@id":"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/jamesonquave.com\/blog\/developing-ios-apps-using-swift-tutorial-part-2\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/jamesonquave.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Developing iOS Apps Using Swift Tutorial Part 2"}]},{"@type":"WebSite","@id":"https:\/\/jamesonquave.com\/blog\/#website","url":"https:\/\/jamesonquave.com\/blog\/","name":"Jameson Quave","description":"Using computer technology to educate, and improve lives.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jamesonquave.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/db6184f355c7f4e3b876d0f228c2fcfc","name":"Jameson Quave","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d9786c83345117d560bbeab0e1f26814?s=96&d=retro&r=pg","caption":"Jameson Quave"},"sameAs":["http:\/\/jamesonquave.com"],"url":"https:\/\/jamesonquave.com\/blog\/author\/jquave\/"}]}},"_links":{"self":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/588"}],"collection":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/comments?post=588"}],"version-history":[{"count":69,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/588\/revisions"}],"predecessor-version":[{"id":2241,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/588\/revisions\/2241"}],"wp:attachment":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/media?parent=588"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/categories?post=588"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/tags?post=588"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}