<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[iOS Programming - AppCoda]]></title><description><![CDATA[AppCoda is one of the leading iOS programming communities. Our goal is to empower everyone to create apps through easy-to-understand tutorials. Learn by doing is the heart of our learning materials. ]]></description><link>https://www.appcoda.com/</link><image><url>https://www.appcoda.com/favicon.png</url><title>iOS Programming - AppCoda</title><link>https://www.appcoda.com/</link></image><generator>Ghost 5.83</generator><lastBuildDate>Fri, 10 Apr 2026 14:38:10 GMT</lastBuildDate><atom:link href="https://www.appcoda.com/tag/ios-programming/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Intermediate iOS Programming with Swift is Now Updated for iOS 15 and Xcode 13]]></title><description><![CDATA[<!--kg-card-begin: html-->
<p>This intermediate book (over 950 pages) uses a problem-solution approach to teach you Swift programming and covers some of the common APIs provided by the iOS SDK including Core ML and ARKit. The book and the source code bundled are now compatible with iOS 15 and <a href="https://developer.apple.com/xcode/?ref=appcoda.com" class="rank-math-link">Xcode 13</a>. </p>



<p>This book</p>]]></description><link>https://www.appcoda.com/intermediate-ios-programming-for-ios-15/</link><guid isPermaLink="false">66612a0f166d3c03cf0114ff</guid><category><![CDATA[iOS Programming]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><dc:creator><![CDATA[Simon Ng]]></dc:creator><pubDate>Wed, 02 Mar 2022 17:54:35 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html-->
<img src="https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15.png" alt="Intermediate iOS Programming with Swift is Now Updated for iOS 15 and Xcode 13"><p>This intermediate book (over 950 pages) uses a problem-solution approach to teach you Swift programming and covers some of the common APIs provided by the iOS SDK including Core ML and ARKit. The book and the source code bundled are now compatible with iOS 15 and <a href="https://developer.apple.com/xcode/?ref=appcoda.com" class="rank-math-link">Xcode 13</a>. </p>



<p>This book is written for developers with some experience on the Swift programming language and with an interest in developing iOS apps. It is not a book for beginners. But if you have some experience in Swift, you will definitely benefit from this book.</p>



<p>While you can start reading from chapter 1 of the book, but this is not a must. Each chapter stands on its own, so you can also treat this book as a reference. Simply pick the chapter that interests you and dives into it.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="1024" src="https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-1024x1024.jpg" alt="Intermediate iOS Programming with Swift is Now Updated for iOS 15 and Xcode 13" class="wp-image-19863" srcset="https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-1024x1024.jpg 1024w, https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-300x300.jpg 300w, https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-200x200.jpg 200w, https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-768x768.jpg 768w, https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-1240x1240.jpg 1240w, https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-860x860.jpg 860w, https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-680x680.jpg 680w, https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-400x400.jpg 400w, https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail-50x50.jpg 50w, https://www.appcoda.com/content/images/wordpress/2022/03/gumroad-intermediate-ios15-thumbnail.jpg 1280w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading">What You&#x2019;ll Learn in this book</h2>



<p>Here are what you will learn in this Intermediate Swift book:</p>



<p>Chapter 1 &#x2013; Adaptive UI Using Universal Storyboards and Size Classes</p>



<p>Chapter 2 &#x2013; Creating Table View Sections and Index list with Diffable Data Source</p>



<p>Chapter 3 &#x2013; Animating Table View Cell</p>



<p>Chapter 4 &#x2013; Reading and Parsing JSON</p>



<p>Chapter 5 &#x2013; How to Integrate Twitter and Facebook Sharing</p>



<p>Chapter 6 &#x2013; How to Create Email with Attachment</p>



<p>Chapter 7 &#x2013; Sending SMS and MMS</p>



<p>Chapter 8 &#x2013; How to Get Direction and Draw Route on Map</p>



<p>Chapter 9 &#x2013; How to Search Points of Interest Using Local Search</p>



<p>Chapter 10 &#x2013; Audio Recording and Playback</p>



<p>Chapter 11 &#x2013; Scan QR code using AVFoundation Framework</p>



<p>Chapter 12 &#x2013; Working with URL Schemes</p>



<p>Chapter 13 &#x2013; Working with Camera</p>



<p>Chapter 14 &#x2013; Video Capturing and Playback using AVKit Framework</p>



<p>Chapter 15 &#x2013; Display Banner Ads using iAd</p>



<p>Chapter 16 &#x2013; Using Custom Fonts</p>



<p>Chapter 17 &#x2013; AirDrop</p>



<p>Chapter 18 &#x2013; Building Grid Layouts Using Collection Views and Diffable Data Source</p>



<p>Chapter 19 &#x2013; Interacting with Collection View</p>



<p>Chapter 20 &#x2013; Adaptive Collection View</p>



<p>Chapter 21 &#x2013; Building a Weather Widget Using WidgetKit</p>



<p>Chapter 22 &#x2013;&#xA0;Building Slide Out Sidebar Menus Using Objective-C Libraries</p>



<p>Chapter 23 &#x2013; View Controller Transitions and Animations</p>



<p>Chapter 24 &#x2013; Building a Slide Down Menu Like Medium App</p>



<p>Chapter 25 &#x2013; Self Sizing Cells and Dynamic Type</p>



<p>Chapter 26 &#x2013; XML Parsing and RSS</p>



<p>Chapter 27 &#x2013; Apply a Blurred Background Using UIVisualEffect</p>



<p>Chapter 28 &#x2013; Using Touch ID for Authentication</p>



<p>Chapter 29 &#x2013; Building a Carousel-like User Interface</p>



<p>Chapter 30 &#x2013; Working with Parse</p>



<p>Chapter 31 &#x2013; How to Preload Existing Data into SQLite Database</p>



<p>Chapter 32 &#x2013; Connecting Multiple Annotations with Polylines and Routes</p>



<p>Chapter 33 &#x2013; Using CocoaPods in Swift Projects</p>



<p>Chapter 34 &#x2013; Building a Simple Sticker App</p>



<p>Chapter 35 &#x2013; Building iMessage Apps Using the Messages Framework</p>



<p>Chapter 36 &#x2013; Building Custom UI Components Using IBDesignable and IBInspectable</p>



<p>Chapter 37 &#x2013; Using Firebase for User Authentication</p>



<p>Chapter 38 &#x2013; Google and Facebook Authentication Using Firebase</p>



<p>Chapter 39 &#x2013; Using Firebase Database and Storage to Build an Instagram-like App</p>



<p>Chapter 40 &#x2013; Introduction to CoreML (Available in late March)</p>



<p>Chapter 41 &#x2013; Building AR Apps with ARKit and SpriteKit</p>



<p>Chapter 42 &#x2013; Working with 3D Objects in Augmented Reality Using ARKit and SceneKit</p>



<p>Chapter 43 &#x2013; Use Create ML to Train Your Own Machine Learning Model for Image Recognition</p>



<p>Chapter 44 &#x2013; Building a Sentiment Classifier Using Create ML to Classify User Reviews</p>



<p>Chapter 45 &#x2013; Working with Image Tracking in ARKit</p>



<h2 class="wp-block-heading">Don&#x2019;t Miss the Launch Discount</h2>



<p>If you want to learn more about <a href="https://www.appcoda.com/intermediate-swift-programming-book/" class="rank-math-link">the book and download a sample</a>, please head over to this link. From now till Mar 6 (23:59 PST), you can use the discount code &#x201C;<strong>NEXTLEVEL</strong>&#x201D; at checkout to receive an extra 20% off.</p>



<p>For beginners, if you want to learn more about Swift, you can check out our beginner book at&#xA0;<a rel="noreferrer noopener" href="https://www.appcoda.com/swift" target="_blank">https://www.appcoda.com/swift</a>.</p>



<p>For SwiftUI, you can check out our new Mastering SwiftUI book (<a target="_blank" rel="noreferrer noopener" href="https://www.appcoda.com/swiftui">https://www.appcoda.com/swiftui</a>).</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[SwiftUI: How to Display Web Page Using WKWebView]]></title><description><![CDATA[<!--kg-card-begin: html-->
<p>It is very common that you need to display web content in your apps. The iOS SDK provides three options for developers to show web content: Mobile Safari, <a href="https://developer.apple.com/documentation/webkit/wkwebview?ref=appcoda.com" class="rank-math-link">WKWebView</a>, and SFSafariViewController. In iOS 14 (or later), the <a href="https://www.appcoda.com/swiftui" class="rank-math-link">SwiftUI framework</a> provides a view called <code>Link</code> for you to open a web</p>]]></description><link>https://www.appcoda.com/swiftui-wkwebview/</link><guid isPermaLink="false">66612a0f166d3c03cf0114fb</guid><category><![CDATA[iOS Programming]]></category><category><![CDATA[SwiftUI]]></category><dc:creator><![CDATA[Simon Ng]]></dc:creator><pubDate>Sun, 24 Oct 2021 22:29:58 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2021/10/webview-0.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html-->
<img src="https://www.appcoda.com/content/images/wordpress/2021/10/webview-0.png" alt="SwiftUI: How to Display Web Page Using WKWebView"><p>It is very common that you need to display web content in your apps. The iOS SDK provides three options for developers to show web content: Mobile Safari, <a href="https://developer.apple.com/documentation/webkit/wkwebview?ref=appcoda.com" class="rank-math-link">WKWebView</a>, and SFSafariViewController. In iOS 14 (or later), the <a href="https://www.appcoda.com/swiftui" class="rank-math-link">SwiftUI framework</a> provides a view called <code>Link</code> for you to open a web link in mobile Safari. The usage is very simple. You just need to specify the text of the link and the destination URL like this:</p>



<pre class="wp-block-code"><code>Link(destination: URL(string: &quot;https://www.appcoda.com&quot;)!, label: {
    Text(&quot;AppCoda&quot;)
        .foregroundColor(.orange)
})</code></pre>



<p>This presents a text link in orange. When a user taps the text, the app opens the link in the Safari browser. You are not limited to use a text link. In the <code>label</code> closure, you can change the code to present an image link using an <code>Image</code> view or other custom views.</p>



<p>However, the current version of SwiftUI doesn&#x2019;t come with an embedded web view. To display web content within your applications, you will need to tap into the UIKit framework. In this tutorial, I will walk you through the procedures to adopt <code>WKWebView</code> in SwiftUI projects.</p>



<h2 class="wp-block-heading">Adopting WKWebView Using UIViewRepresentable</h2>



<p>Assuming you have some experience with the integration of SwiftUI and UIKit, you know we need to adopt <a href="https://www.appcoda.com/swiftui-textview-uiviewrepresentable/">the <code>UIViewRepresentable</code> protocol</a> to use the components from UIKit.</p>



<p>For this demo, I will create a new file called <code>WebView.swift</code> to implement a custom web view for SwiftUI. In the project navigator, right click the project folder and choose <em>New File&#x2026;</em>. Select the <em>Swift File</em> template and name the file <code>WebView.swift</code>. Replace the file content like this:</p>



<pre class="wp-block-code"><code>import SwiftUI
import WebKit

struct WebView: UIViewRepresentable {

    var url: URL

    func makeUIView(context: Context) -&gt; WKWebView {
        return WKWebView()
    }

    func updateUIView(_ webView: WKWebView, context: Context) {
        let request = URLRequest(url: url)
        webView.load(request)
    }
}</code></pre>



<p>To use a UIKit view in SwiftUI, you wrap the view with the <code>UIViewRepresentable</code> protocol. Basically, you just need to create a <code>struct</code> in SwiftUI that adopts the protocol to create and manage a <code>UIView</code> object. In the code above, we create a <code>WebView</code> struct adopts the <code>UIViewRepresentable</code> protocol and implement the required methods.</p>



<p>In the <code>makeUIView</code> method, we return an instance of <code>WKWebView</code>. This is how you wrap a UIKit view and make the web view available to SwiftUI.</p>



<p>While the <code>makeUIView</code> method is responsible for creating and initializing the view object, the <code>updateUIView</code> method is responsible for updating the state of the UIKit view. So, we load the given URL in the <code>updateUIView</code> method.</p>



<p>Now it is ready to use <code>WebView</code> in our SwiftUI project. Switch over to <code>ContentView.swift</code> and add a state variable to store the current link:</p>



<pre class="wp-block-code"><code>@State private var showWebView = false</code></pre>



<p>To bring up the web view, attach the <code>.sheet</code> modifier to the <code>Button</code> view:</p>



<pre class="wp-block-code"><code>Button {
    showWebView.toggle()
} label: {
    Text(&quot;AppCoda&quot;)
}
.sheet(isPresented: $showWebView) {
    WebView(url: URL(string: &quot;https://www.appcoda.com&quot;)!)
}</code></pre>



<p>We present the custom web view using a sheet. You can run the app on a simulator to have a test. When you tap the button, the app brings up a web view to load the website in a modal view.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1920" height="923" src="https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview.png" alt="SwiftUI: How to Display Web Page Using WKWebView" class="wp-image-19661" srcset="https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview.png 1920w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-600x288.png 600w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-1024x492.png 1024w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-200x96.png 200w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-768x369.png 768w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-1536x738.png 1536w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-1680x808.png 1680w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-1240x596.png 1240w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-860x413.png 860w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-680x327.png 680w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-400x192.png 400w, https://www.appcoda.com/content/images/wordpress/2021/10/swiftui-webview-50x24.png 50w" sizes="(max-width: 1920px) 100vw, 1920px"></figure>



<p>By using the same technique, you can integrate <code>SFSafariViewController</code> in your SwiftUI projects. I will leave it to you as an exercise.</p>



<p>If you want to learn more about SwiftUI, you can check out <a href="https://www.appcoda.com/swift">our updated Swift course</a>.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Adding a Launch Screen in Swift Projects]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>A <a href="https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/launch-screen/?ref=appcoda.com" class="rank-math-link">launch screen</a> is the very first screen presented to users when your app starts up. When you create a new project with UIKit, Xcode automatically generates a storyboard file named <code>LaunchScreen.storyboard</code> for developers to design the launch screen of the app. However, if you are developing an app</p>]]></description><link>https://www.appcoda.com/launch-screen-swiftui/</link><guid isPermaLink="false">66612a0f166d3c03cf0114ef</guid><category><![CDATA[iOS Programming]]></category><dc:creator><![CDATA[Simon Ng]]></dc:creator><pubDate>Tue, 25 May 2021 16:19:42 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2021/05/6wdruk7bvte.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2021/05/6wdruk7bvte.jpg" alt="Adding a Launch Screen in Swift Projects"><p>A <a href="https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/launch-screen/?ref=appcoda.com" class="rank-math-link">launch screen</a> is the very first screen presented to users when your app starts up. When you create a new project with UIKit, Xcode automatically generates a storyboard file named <code>LaunchScreen.storyboard</code> for developers to design the launch screen of the app. However, if you are developing an app with the SwiftUI framework, the launch screen file is no longer there. So, how can you prepare a launch screen in SwiftUI projects?</p>



<p>In <a href="https://www.appcoda.com/xcode-12-swift-53/" class="rank-math-link">Xcode 12</a>, the tool provides a new way to implement a launch screen in SwiftUI. I will walk you through the procedures in this tutorial.</p>



<p><strong>Editor&#x2019;s note</strong>: If you want to learn SwiftUI, check out our <a href="https://www.appcoda.com/swiftui" class="rank-math-link">Mastering SwiftUI</a> book.</p>



<h2 class="wp-block-heading">Preparing the Launch Image and Color Set</h2>



<p>The figure below shows the launch screen we are going to build. It&#x2019;s very simple screen that displays an image at the center of the view. The launch screen also adapts to different background color for Light and <a href="https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/dark-mode?ref=appcoda.com" class="rank-math-link">Dark mode</a>.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1920" height="1117" src="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2.png" alt="Adding a Launch Screen in Swift Projects" class="wp-image-19301" srcset="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2.png 1920w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-516x300.png 516w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-1024x596.png 1024w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-200x116.png 200w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-768x447.png 768w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-1536x894.png 1536w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-1680x977.png 1680w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-1240x721.png 1240w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-860x500.png 860w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-680x396.png 680w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-400x233.png 400w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-2-50x29.png 50w" sizes="(max-width: 1920px) 100vw, 1920px"></figure>



<p>To implement the launch screen above, you should first prepare the image and import it into the asset catalog.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1508" height="374" src="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset.png" alt="Adding a Launch Screen in Swift Projects" class="wp-image-19302" srcset="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset.png 1508w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset-600x149.png 600w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset-1024x254.png 1024w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset-200x50.png 200w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset-768x190.png 768w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset-1240x308.png 1240w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset-860x213.png 860w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset-680x169.png 680w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset-400x99.png 400w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-image-asset-50x12.png 50w" sizes="(max-width: 1508px) 100vw, 1508px"></figure>



<p>Since the app supports both Light and Dark modes, we need to create a new color asset for the background color.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1920" height="713" src="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3.png" alt="Adding a Launch Screen in Swift Projects" class="wp-image-19303" srcset="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3.png 1920w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-600x223.png 600w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-1024x380.png 1024w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-200x74.png 200w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-768x285.png 768w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-1536x570.png 1536w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-1680x624.png 1680w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-1240x460.png 1240w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-860x319.png 860w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-680x253.png 680w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-400x149.png 400w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-3-50x19.png 50w" sizes="(max-width: 1920px) 100vw, 1920px"></figure>



<p>Name the color set <em>LaunchScreenBackground</em> and set the color code to the following:</p>



<ul><li>Any appearance &#x2013; #EEEEEE</li><li>Dark appearance &#x2013; #111111</li></ul>



<h2 class="wp-block-heading">Adding a Launch Screen</h2>



<p>In SwiftUI projects, the launch screen is not generated by default. You need to add it manually in the <code>Info.plist</code> file. After opening the file, you should see an entry named <em>Launch Screen</em>. Click the arrow on its left to change the direction. Then click the <code>+</code> button to add a new entry.</p>



<p>There are a number of options for you to choose from. To configure the background color, set the key to <code>Background color</code> and value to <code>LaunchScreenBackground</code>, which is the color set created in the previous section.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="302" src="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-1024x302.png" alt="Adding a Launch Screen in Swift Projects" class="wp-image-19304" srcset="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-1024x302.png 1024w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-600x177.png 600w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-200x59.png 200w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-768x226.png 768w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-1240x365.png 1240w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-860x253.png 860w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-680x200.png 680w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-400x118.png 400w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4-50x15.png 50w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-4.png 1432w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>To include an image in the launch screen, click the <code>+</code> button to add another key. Set it to <code>Image Name</code>. For its value, set it to the name of the image (i.e. <code>ramen</code>) we imported.</p>



<p>If we want to ensure the image stays within the safe area, add the <code>Image respects safe area insets</code> and set its value to <code>YES</code>. The rest of the options are used for configuring the appearance of the navigation bar, tab bar, and toolbar. It&#x2019;s up to your preference to enable them or not.</p>



<p>Once you complete the configuration, you can hit the <em>Play</em> button to run the app on a simulator. When the app is launched, it should display the launch screen. The background color adapts itself to the underlying interface style.</p>



<p>In case if your simulator couldn&#x2019;t bring up the launch screen, go up to the simulator menu and click <em>Device &gt; Restart</em> to clear its cache.</p>



<h2 class="wp-block-heading">Using LaunchScreen.storyboard</h2>



<p>Can you still use the old way to create a launch screen in SwiftUI projects? Yes, Xcode 12 still allows developers to do so. However, Xcode no longer generates the <code>LaunchScreen.storyboard</code> file for you. You have to add it manually by creating a new file using the <em>Launch Screen</em> template.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1482" height="1056" src="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file.png" alt="Adding a Launch Screen in Swift Projects" class="wp-image-19305" srcset="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file.png 1482w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file-421x300.png 421w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file-1024x730.png 1024w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file-200x143.png 200w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file-768x547.png 768w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file-1240x884.png 1240w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file-860x613.png 860w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file-680x485.png 680w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file-400x285.png 400w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-storyboard-file-50x36.png 50w" sizes="(max-width: 1482px) 100vw, 1482px"></figure>



<p>And then, you can set the launch screen option in the project configuration.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="2898" height="1020" src="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting.png" alt="Adding a Launch Screen in Swift Projects" class="wp-image-19306" srcset="https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting.png 2898w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-600x211.png 600w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-1024x360.png 1024w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-200x70.png 200w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-768x270.png 768w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-1536x541.png 1536w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-2048x721.png 2048w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-1680x591.png 1680w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-1240x436.png 1240w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-860x303.png 860w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-680x239.png 680w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-400x141.png 400w, https://www.appcoda.com/content/images/wordpress/2021/05/launchscreen-setting-50x18.png 50w" sizes="(max-width: 2898px) 100vw, 2898px"></figure>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[The Complete Guide to PHPicker API in iOS 14]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>Importing photos and videos as media items is one of the most common features that the majority of iOS applications include. In general lines, there are two ways to do that; either by using a system-provided controller, or by implementing a custom picker manually. Obviously, going with the second approach</p>]]></description><link>https://www.appcoda.com/phpicker/</link><guid isPermaLink="false">66612a0f166d3c03cf0114e6</guid><category><![CDATA[iOS Programming]]></category><dc:creator><![CDATA[Gabriel Theodoropoulos]]></dc:creator><pubDate>Fri, 22 Jan 2021 00:29:38 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2021/01/fwoh2qhlb5i.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2021/01/fwoh2qhlb5i.jpg" alt="The Complete Guide to PHPicker API in iOS 14"><p>Importing photos and videos as media items is one of the most common features that the majority of iOS applications include. In general lines, there are two ways to do that; either by using a system-provided controller, or by implementing a custom picker manually. Obviously, going with the second approach is a much harder and complicated process.</p>



<p>In this post we are going to focus on the first option, and particularly on a brand new photo picker controller that was first introduced in <a href="https://www.appcoda.com/colorpicker-datepicker/" class="rank-math-link">iOS 14</a>. That is the <strong>PHPicker API</strong>! Let&#x2019;s take a look at a few interesting and useful details, but let&#x2019;s do that starting from a different point.</p>



<p>Up until iOS 13, the available photo picker to use had been the <em>UIImagePickerController</em>; a familiar view controller that made its debut many years back. <a href="https://www.appcoda.com/swiftui-camera-photo-library/" class="rank-math-link">UIImagePickerController</a> has been providing double functionality; the first is photo and videos importing to the app, and the other capture of new media using a camera from the iPhone or iPad.</p>



<p>This controller, however, carries along two disadvantages; the first is that it provides a relatively limited environment to pick media items from. Users can select one photo or video at each time only, while there&#x2019;s no option to search for specific items when there are many of those stored in user&#x2019;s library. The second downside is that developers are required to ask from users for their consent in order to present it, and therefore add new entries in the app&#x2019;s Info.plist file with a description of the intended use.</p>



<p>PHPicker changes all that, and makes importing photos and videos an easier and faster task. First of all, its greatest feature is that it allows <strong>both single and multiple item selection</strong>, a feature that is definitely much appreciated by users. In addition, it offers a <strong>search feature</strong> in a <em>picker similar to the Photos app</em>, so users meet a familiar place; they already know how to move and what to do when such a picker is presented to them.</p>



<p>Also, and contrarily to the UIImagePickerController, PHPicker provides a better privacy and does not require to ask for user consent so it can be used. Even though an app can trigger its presentation, <strong>the picker runs in a separate process</strong> where users can select only type of media necessary for their tasks, and do nothing beyond that; not even to get a snapshot of the picker. So, with PHPicker, simply forget about usage descriptions and rely on the built-in iOS privacy.</p>



<p>To get the photos and videos that users have picked and handle them in our apps, PHPicker transfers them over temporarily and offers a few ways to fetch them. We are going to see all the related how-to in the upcoming parts of this post. However, before we continue, keep something important in mind; <em>PHPicker is not a class, nor a framework</em>. It&#x2019;s just a name that hides classes and other types behind it, where all of them belong to the <a href="https://developer.apple.com/documentation/photokit?ref=appcoda.com" class="rank-math-link"><em>PhotosUI</em> framework</a>, also announced in WWDC 2020.</p>



<p>What PHPicker does not do is to offer capture capabilities. If an app wants to do so, then the UIImagePickerController is still the way to go. Also, apps running on iOS 13 and below cannot use PHPicker APIs; it&#x2019;s meant for iOS 14 and above only.</p>



<p>That being said, in this tutorial we are going to meet PHPicker and all necessary actions that will let us import photos, videos and live photos to a demo application. We will have the chance to talk about some not so much known techniques, and we&#x2019;ll see various aspects of PHPicker, such as how to configure it or how to handle picked items. In the mix we will also add pinches of SwiftUI, so get ready for a really interesting post!</p>



<h2 class="wp-block-heading">An Overview Of The Demo App</h2>



<p>In order to get a good, in-depth taste of PHPicker, we are going to be working on a simple demo application. It&#x2019;s about a single-screen SwiftUI app, and there is a <a href="https://github.com/appcoda/PHPickerDemo/tree/main/starter/PHPickerDemo?ref=appcoda.com" class="rank-math-link">starter project to download</a> that I&#x2019;ve prepared for you.</p>



<p>Once you download and open it in Xcode, you&#x2019;ll find a few files in the Project navigator:</p>



<ul><li>ItemsView.swift: The SwiftUI view that we&#x2019;ll be working on.</li><li>PhotoPicker.swift: This is where we&#x2019;ll do the PHPicker related work.</li><li>PhotoPickerModel.swift: A place where we&#x2019;ll implement a custom model to keep data about selected media items.</li><li>LivePhotoView.swift: It will become handy in order to preview live photos in the demo app.</li></ul>



<p>I&#x2019;m not going to provide any details about the contents of these files, as we are just about to see thoroughly next.</p>



<p>In the ItemsView there&#x2019;s some initial code already implemented. Even though we won&#x2019;t perform any navigation, there is a NavigationView added in order to create a navigation bar and therefore to have two bar buttons; one for adding new media items to the app (a plus icon), and one for deleting them (a trash icon).</p>



<p>The main content of the view is practically empty. There is an EmptyView that we are going to replace soon with a List view, and inside that List we are going to display the various media that we will be importing. There is also a <em>sheet</em> ready to be used; with it we&#x2019;ll be presenting the photo picker.</p>



<p>Take your time to look around in the starter project, and once you&#x2019;re done, then just keep reading. A quite interesting and detailed tutorial is just about to unfold.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="553" height="1024" src="https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-553x1024.png" alt="The Complete Guide to PHPicker API in iOS 14" class="wp-image-19012" srcset="https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-553x1024.png 553w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-162x300.png 162w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-200x370.png 200w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-400x740.png 400w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-50x93.png 50w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items.png 568w" sizes="(max-width: 553px) 100vw, 553px"></figure></div>



<h2 class="wp-block-heading">Presenting The PHPicker View Controller</h2>



<p>Let&#x2019;s start working in order to present the <a href="https://developer.apple.com/documentation/photokit/phpickerviewcontroller?ref=appcoda.com" class="rank-math-link">PHPicker controller</a>. We are going to show it modally, and for that job we are going to employ the sheet in the ItemsView; presenting content modally is what a sheet is meant for.</p>



<p>In the demo application doing so has already been taken care of:</p>



<pre class="wp-block-code"><code>.sheet(isPresented: $showSheet, content: {

})</code></pre>



<p>In the ItemsView.swift file you will find the <code>sheet</code> view modifier right after the closing of the NavigationView. This is what presents the actual sheet, but the flag that controls whether the sheet should be presented or not is the <code>showSheet</code> property that has been marked with the <code>@State</code> property wrapper:</p>



<pre class="wp-block-code"><code>@State private var showSheet = false</code></pre>



<p>The <code>sheet</code> modifier gets two arguments:</p>



<ol><li>The <em>binding value</em> of the @State property that indicates whether sheet should be shown or not. That binding value is the <code>$showSheet</code> argument in code, and it means that content inside the sheet can change the value of <code>showSheet</code>, which belongs to ItemsView.</li><li>A closure where we&#x2019;ll provide the sheet&#x2019;s content; soon this will be the picker controller.</li></ol>



<p>The PHPicker controller is a <em>UIKit view controller</em>, represented by the <strong>PHPickerViewController</strong> class. Since it&#x2019;s not a native SwiftUI component, unavoidably we will mix SwiftUI and UIKit together.</p>



<p>In order to make a UIKit view controller available to <a href="https://www.appcoda.com/swiftui" class="rank-math-link">SwiftUI</a> and accessible in it, it&#x2019;s necessary to create a new custom type, a structure, that will be conforming to a specific protocol called <em>UIViewControllerRepresentable</em>. That structure will actually be implementing and dealing with the UIKit view controller, and it will be the bridge between the controller and the SwiftUI view that is meant to be making use of it.</p>



<p>Let&#x2019;s see that happening in action, but for keeping our code as clean and readable as possible, let&#x2019;s work on a different file. That is the <em>PhotoPicker.swift</em> in the starter project, so just click on it to open and start editing it.</p>



<p>The first step is to replace the Foundation framework imported by default with the following two:</p>



<pre class="wp-block-code"><code>import SwiftUI
import PhotosUI</code></pre>



<p>The SwiftUI framework is needed so we can use the UIViewControllerRepresentable protocol; the PhotosUI for accessing the PHPickerViewController class.</p>



<p>Next, let&#x2019;s define a custom type, which is going to be a structure and we&#x2019;ll call <em>PhotoPicker</em>. Don&#x2019;t forget that it has to be conforming to the UIViewControllerRepresentable protocol:</p>



<pre class="wp-block-code"><code>struct PhotoPicker: UIViewControllerRepresentable {

}</code></pre>



<p>Every UIViewControllerRepresentable type must be necessarily doing the following three things:</p>



<ol><li>To specify the view controller type that is dealing with.</li><li>To implement a method where it creates, configures and returns the view controller instance.</li><li>To implement one more method that is used in order to perform updates to the view controller when those originate from the SwiftUI environment. Even though it&#x2019;s mandatory to define it, this method can remain empty if there is no reason to update the view controller. And that&#x2019;s what we&#x2019;ll do here; we&#x2019;ll just leave it empty.</li></ol>



<p>Having said all that, let&#x2019;s see how they are all implemented in the <code>PhotoPicker</code> structure:</p>



<pre class="wp-block-code"><code>struct PhotoPicker: UIViewControllerRepresentable {
    typealias UIViewControllerType = PHPickerViewController

    func makeUIViewController(context: Context) -&gt; PHPickerViewController {

    }

    func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {

    }
}</code></pre>



<p>We&#x2019;ll now focus on the <code>makeUIViewController(context:)</code> method, as that&#x2019;s the place where we&#x2019;ll initialize the picker view controller. At the initilization time of a PHPickerViewController object, we must provide the desired configuration that should apply to the picker when it will be presented. That configuration is given as a <em>PHPickerConfiguration</em> object, which is another PHPicker API.</p>



<p>Initially we&#x2019;ll start simple, by allowing to pick only photos. Also, at first we&#x2019;ll limit the number of allowed picked items to one (1), but that&#x2019;s something we are going to change later. In order to do all that, at first we have to create a new PHPickerConfiguration object:</p>



<pre class="wp-block-code"><code>func makeUIViewController(context: Context) -&gt; PHPickerViewController {
    var config = PHPickerConfiguration()
    config.filter = .images
    config.selectionLimit = 1
}</code></pre>



<p>It&#x2019;s also necessary to specify the value of one more property of the <code>config</code> object:</p>



<pre class="wp-block-code"><code>config.preferredAssetRepresentationMode = .current</code></pre>



<p>Even though the documentation of that property is actually empty on Apple docs, the import process is going to take significantly too much time in order to complete without setting <code>current</code> to <code>preferredAssetRepresentationMode</code>. So, add the above along with the other two configurable properties.</p>



<p>With the configuration object ready, we can move on and initialize a PHPickerViewController instance, and eventually return it from the method:</p>



<pre class="wp-block-code"><code>func makeUIViewController(context: Context) -&gt; PHPickerViewController {
    ...

    let controller = PHPickerViewController(configuration: config)

    // Set the delegate here...

    return controller
}</code></pre>



<p>See that we are passing the <code>config</code> in the initializer of the <code>controller</code> object at the time of its creation. Also, right before the return statement, there is a comment I added there about setting the delegate. And here is why:</p>



<p>A user will have two choices once the picker controller has been presented; either to pick a photo to import, or to cancel and dismiss the picker. In any case, the selected action will be communicated back through a delegate method, which we obviously have to implement and handle the results. However, at this point we still don&#x2019;t have the object that we will set as the picker&#x2019;s delegate. And it cannot be the PhotoPicker instance; it has to be a class instance. In particular for UIViewControllerRepresentable types, a <em>coordinator</em> class is playing that role.</p>



<h3 class="wp-block-heading">Implementing The Coordinator Class</h3>



<p>A coordinator class is a custom type that has to be implemented <em>inside</em> a UIViewControllerRepresentable type, in our case inside the PhotoPicker structure, and it has a quite specific purpose; to act as the delegate for view controllers that send messages through delegate methods, and pass received data to SwiftUI. If we could phrase that in simpler words, just think that this is the way for a UIKit view controller to send messages to the SwiftUI view that is using it.</p>



<p>It all starts by defining the following class in the PhotoPicker body:</p>



<pre class="wp-block-code"><code>struct PhotoPicker: UIViewControllerRepresentable {
    ...

    class Coordinator {

    }
}</code></pre>



<p>In the class body, we will declare the following property which will be keeping the PhotoPicker instance:</p>



<pre class="wp-block-code"><code>class Coordinator {
    var photoPicker: PhotoPicker
}</code></pre>



<p>Along with that, we&#x2019;ll also create a custom initializer method:</p>



<pre class="wp-block-code"><code>class Coordinator {
    var photoPicker: PhotoPicker

    init(with photoPicker: PhotoPicker) {
        self.photoPicker = photoPicker
    }
}</code></pre>



<p>Now, and before we go any further, it&#x2019;s the best time to create a Coordinator instance in the PhotoPicker structure by using an optional method of the UIViewControllerRepresentable protocol. That method will simply initialize and return a Coordinator object, passing the PhotoPicker instance (<code>self</code>) as an argument:</p>



<pre class="wp-block-code"><code>struct PhotoPicker: UIViewControllerRepresentable {
    ...

    func makeCoordinator() -&gt; Coordinator {
        Coordinator(with: self)
    }

    class Coordinator { ... }
}</code></pre>



<p>Back to the <code>makeUIViewController(context:)</code> method, we are now able to replace the following comment:</p>



<pre class="wp-block-code"><code>// Set the delegate here...</code></pre>



<p>with this:</p>



<pre class="wp-block-code"><code>controller.delegate = context.coordinator</code></pre>



<p>Notice that the Coordinator instance is accessible through the <code>context</code> parameter value of the method. After having added the above, here&#x2019;s the entire method:</p>



<pre class="wp-block-code"><code>func makeUIViewController(context: Context) -&gt; PHPickerViewController {
    var config = PHPickerConfiguration()
    config.filter = .images
    config.selectionLimit = 1
    config.preferredAssetRepresentationMode = .current

    let controller = PHPickerViewController(configuration: config)
    controller.delegate = context.coordinator
    return controller
}</code></pre>



<h3 class="wp-block-heading">The PHPicker Delegate Method</h3>



<p>We can now pay our full attention to the implementation of the Coordinator class. At first, it&#x2019;s necessary to make it conform to the <em>PHPickerViewControllerDelegate</em> protocol; the one that will provide us with the delegate method that has to be implemented:</p>



<pre class="wp-block-code"><code>class Coordinator: PHPickerViewControllerDelegate {
    ...
}</code></pre>



<p>Even though two different kind of actions can take place in the picker view controller after it has been presented (pick photos or cancel), there is one delegate method to implement only. This is called both when user selects media items, and when just cancels and dismisses the picker. This is the following:</p>



<pre class="wp-block-code"><code>class Coordinator: PHPickerViewControllerDelegate {
    ...

    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {

    }
}</code></pre>



<p>See that the selected items are contained in the <code>results</code> parameter; it&#x2019;s a collection of <em>PHPickerResult</em> objects, which we&#x2019;ll deal with in a while.</p>



<p>At this point, there is a question rising; how are we supposed to let the SwiftUI view know that the picker has been dismissed, and whether the user selected items or just cancelled?</p>



<p>This question does not include the actual selected media items. Those will be handled <em>asynchronously</em> and we&#x2019;ll provide them to the SwiftUI view in a different way which we&#x2019;ll implement next. But to answer and come up to a solution, first we have to consider something else.</p>



<p>The time that the picker will be dismissed is undefined and depends totally on the user. We can&#x2019;t predict it and the best approach in order to react to that is by defining and using an <em>action handler</em>. That action handler will be called in the delegate method, but it will be implemented <em>as a closure</em> in the SwiftUI view, provided to the PhotoPicker instance right at the time of the initialization. Then, each app will be able to trigger any necessary further actions once it has the information that the picker has been dismissed.</p>



<p>So, in the PhotoPicker structure, add the following declaration at the top:</p>



<pre class="wp-block-code"><code>struct PhotoPicker: UIViewControllerRepresentable {
    var didFinishPicking: (_ didSelectItems: Bool) -&gt; Void

    ...
}</code></pre>



<p>The argument that we&#x2019;ll provide to the above callback will be indicating whether the user just dismissed the picker, or that happened after having selected media items.</p>



<p>Returning to the <code>picker(_:didFinishPicking:)</code> delegate method now, we can add the first line of code which will be calling the above callback, passing the proper value as argument:</p>



<pre class="wp-block-code"><code>func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    photoPicker.didFinishPicking(!results.isEmpty)
}</code></pre>



<p>If the <code>results</code> array is not empty and the user has selected media items, then the argument above will be true. Otherwise, it&#x2019;s going to be false. Notice also that we are accessing it through the <code>photoPicker</code> property of the Coordinator class; <code>photoPicker</code> has been declared for accessing PhotoPicker properties like what we just did above.</p>



<p>If the user simply dismissed the picker, then there&#x2019;s nothing to do besides than just returning from the method. We will proceed if only the <code>results</code> array is not empty, but we&#x2019;ll work on that in just a while. For now, let&#x2019;s append the following to the delegate method:</p>



<pre class="wp-block-code"><code>func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    ...

    guard !results.isEmpty else {
        return
    }
}</code></pre>



<p>We can now go back to the ItemsView.swift file, and create a PhotoPicker instance in the sheet&#x2019;s content body:</p>



<pre class="wp-block-code"><code>.sheet(isPresented: $showSheet, content: {
    PhotoPicker() { didSelectItems in
        // Handle didSelectItems value here...
        showSheet = false
    }
})</code></pre>



<p>Here we won&#x2019;t deal with the value of the <code>didSelectItems</code> parameter of the closure, but see the comment I&#x2019;ve put in the above snippet; that&#x2019;s the place to check whether it&#x2019;s true or false, meaning to determine if the user has selected items or not, and then act accordingly.</p>



<p>The only thing we&#x2019;re doing here is to toggle the value of the <code>showSheet</code> property and set it to false. Doing so will cause the dismissal of the sheet, and eventually of the photo picker.</p>



<p>You can give the app a first try at this point, however you&#x2019;ll get the same result no matter if you select a photo or just cancel. The picker will simply get dismissed.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="553" height="1024" src="https://www.appcoda.com/content/images/wordpress/2021/01/t79_1_phpicker_first_run-553x1024.png" alt="The Complete Guide to PHPicker API in iOS 14" class="wp-image-19013" srcset="https://www.appcoda.com/content/images/wordpress/2021/01/t79_1_phpicker_first_run-553x1024.png 553w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_1_phpicker_first_run-162x300.png 162w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_1_phpicker_first_run-200x370.png 200w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_1_phpicker_first_run-400x740.png 400w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_1_phpicker_first_run-50x93.png 50w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_1_phpicker_first_run.png 568w" sizes="(max-width: 553px) 100vw, 553px"></figure>



<h2 class="wp-block-heading">Implementing A Model To Store Picked Items Data</h2>



<p>We managed to present the PHPicker view controller without much effort, but it&#x2019;s practically not useful at all right now. We haven&#x2019;t done any results handling yet, but even if we proceed to that now, where exactly are we going to store the fetched photos?</p>



<p>We have to come up with a solution to that, and that&#x2019;s why in this part we&#x2019;ll focus on the implementation of a basic data model. It will let us keep photos, videos and live photos once we have extracted them from the results in the picker delegate method.</p>



<p>So, to work our way towards that, we&#x2019;ll open the PhotoPickerModel.swift file to add some new code there.</p>



<p>As before, the first thing we&#x2019;ll do in this file is to replace the Foundation framework with the next two:</p>



<pre class="wp-block-code"><code>import SwiftUI
import Photos</code></pre>



<p>After that, let&#x2019;s define the following structure:</p>



<pre class="wp-block-code"><code>struct PhotoPickerModel {

}</code></pre>



<p>Inside the PhotoPickerModel we will define another custom type, an <em>enumeration</em> with cases that will be indicating the type of the media that an instance of this structure is holding:</p>



<pre class="wp-block-code"><code>struct PhotoPickerModel {
    enum MediaType {
        case photo, video, livePhoto
    }
}</code></pre>



<p>One of the tasks that we&#x2019;ll perform later, will be to present a <em>collection of PhotoPickerModel</em> items in a SwiftUI List view. A List, as well as some other views, need each item in the collection to be <em>uniquely identified</em> by some value if possible. We can avoid do that and ask SwiftUI to create unique values automatically. Indeed, it will do that by <em>calculating the hash value of each item</em>, but it&#x2019;s always a better option to provide our own.</p>



<p>In fact, that can be done really easily, as long as we make the PhotoPickerModel conform to a specific protocol called <em>Identifiable</em>. That protocol has one requirement only; the custom type that adopts it to have a property called <code>id</code>. It can be of any type we want, but we must ensure that it&#x2019;s going to have a unique value for each instance of the PhotoPickerModel.</p>



<p>There are various ways to generate unique values, but in order to keep things simple in this tutorial we are going to use <em>UUID</em> strings as id values. According to Apple docs, a UUID is:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>A universally unique value that can be used to identify types, interfaces, and other items.</p></blockquote>



<p>So, with all that in mind, let&#x2019;s update the PhotoPickerModel as shown next:</p>



<pre class="wp-block-code"><code>struct PhotoPickerModel: Identifiable {
    ...

    var id: String
}</code></pre>



<p>Now we can continue on declaring properties that will be storing the various media items we can get from the photo picker.</p>



<p>Let&#x2019;s start with normal photos. In that case we are talking about images, so we need to declare a UIImage property:</p>



<pre class="wp-block-code"><code>var photo: UIImage?</code></pre>



<p>Things change when it&#x2019;s about videos. As we will see in details next, a video cannot be fetched as a single object. When dealing with videos, we&#x2019;ll unavoidably be dealing with files, so what we actually need to store here is the <em>URL</em> to the file containing a picked video:</p>



<pre class="wp-block-code"><code>var url: URL?</code></pre>



<p>Apart from the above two media types, PHPicker also allows to import live photos. A live photo can be taken as a single object, just like normal images can, but there is a specific data type to use here; the <em>PHLivePhoto</em>:</p>



<pre class="wp-block-code"><code>var livePhoto: PHLivePhoto?</code></pre>



<p>Finally, there&#x2019;s one last property that has to be declared. That is the type of the media:</p>



<pre class="wp-block-code"><code>var mediaType: MediaType = .photo</code></pre>



<p>Providing a default initial value (<code>photo</code> here) helps avoid to declare the above as an optional, and therefore make some future tasks easier.</p>



<p>That&#x2019;s all we need, so here&#x2019;s how the PhotoPickerModel has become after having added all the above:</p>



<pre class="wp-block-code"><code>struct PhotoPickerModel: Identifiable {
    enum MediaType {
        case photo, video, livePhoto
    }

    var id: String
    var photo: UIImage?
    var url: URL?
    var livePhoto: PHLivePhoto?
    var mediaType: MediaType = .photo
}</code></pre>



<p>See that the <code>photo</code>, <code>url</code> and <code>livePhoto</code> have been declared as optional properties, meaning that their default value is nil. That makes sense, if you think that when a PhotoPickerModel item stores the data of a specific media type, just one property will get an actual value; there will be no values to assign to the other two properties.</p>



<p>In addition to all the above, we will also implement a few custom initializer methods in order to provide a convenient way to store each media type. Let&#x2019;s start with the case of photos:</p>



<pre class="wp-block-code"><code>init(with photo: UIImage) {
    id = UUID().uuidString
    self.photo = photo
    mediaType = .photo
}</code></pre>



<p>Three distinct things take place here:</p>



<ol><li>We create the unique identifier for the current item.</li><li>We keep the photo to the <code>photo</code> property.</li><li>We provide the proper MediaType value to the <code>mediaType</code> property. In this case, doing that might looks redundant as <code>photo</code> is the default value for <code>mediaType</code>, however it makes no harm to be specific.</li></ol>



<p>The implementation of the initializers for the other two media types is going to be done in an exact similar fashion, so let&#x2019;s see them together:</p>



<pre class="wp-block-code"><code>init(with videoURL: URL) {
    id = UUID().uuidString
    url = videoURL
    mediaType = .video
}

init(with livePhoto: PHLivePhoto) {
    id = UUID().uuidString
    self.livePhoto = livePhoto
    mediaType = .livePhoto
}</code></pre>



<p>In both of them we assign the parameter object to the matching property, and we set the correct media type value. Of course, we create a unique id value as well.</p>



<p>For now the PhotoPickerModel is finished, but we&#x2019;ll come back to it one more time in order to add a handy method we&#x2019;ll need later.</p>



<h2 class="wp-block-heading">The PickedMediaItems Class</h2>



<p>Even though we just implemented the PhotoPickerModel structure, we can&#x2019;t just use it as is. We need one more custom type that will actually be keeping an array of such objects. Besides from just being the place where we&#x2019;ll be storing media items once they have been extracted from the picker results, it will also be the datasource for the List view we&#x2019;ll show in the ItemsView.</p>



<p>While still being in the PhotoPickerModel.swift file, go after the closing curly bracket of the PhotoPickerModel structure and add the next class:</p>



<pre class="wp-block-code"><code>class PickedMediaItems: ObservableObject {

}</code></pre>



<p>It conforms to ObservableObject protocol for one reason; to make it possible to inform SwiftUI views about changes happening to the array we are declaring right next simply by annotating it with the <em>@Published</em> property wrapper.</p>



<pre class="wp-block-code"><code>class PickedMediaItems: ObservableObject {
    @Published var items = [PhotoPickerModel]()
}</code></pre>



<p><code>items</code> array is a collection of PhotoPickerModel objects. When items will be added to that array, or removed from it, the ItemsView will be notified about that right before the change actually takes place. As a result, it will re-render the entire view, and the displayed content will be in harmony with the contents of the <code>items</code> collection.</p>



<p>Of course, marking <code>items</code> with the @Published property wrapper is not enough for what I just described to happen; there&#x2019;s a counterpart action we have to take in the ItemsView as well, but before we get to that, let&#x2019;s add the following method to the PickedMediaItems class just for our own convenience:</p>



<pre class="wp-block-code"><code>class PickedMediaItems: ObservableObject {
    ...

    func append(item: PhotoPickerModel) {
        items.append(item)
    }
}</code></pre>



<p>The only thing the above method does, is to append the given argument to the <code>items</code> array. As said, it&#x2019;s here just to make storing new items faster. Later we&#x2019;ll make one more addition to the PickedMediaItems class, but for now we are good to go.</p>



<p>Let&#x2019;s go to the ItemsView.swift file now, and at the beginning of the ItemsView structure, right where the declaration of the <code>showSheet</code> @State property is, add the following:</p>



<pre class="wp-block-code"><code>struct ItemsView: View {
    @ObservedObject var mediaItems = PickedMediaItems()

    ...
}</code></pre>



<p><code>mediaItems</code> property is an instance of the PickedMediaItems class. By marking it with the @ObservedObject property wrapper, we enable the view to observe for and react to changes that happen to the <code>items</code> array that was annotated as @Published in the PickedMediaItems class. Now, whenever a change occur to that array, view will be re-rendered in order to show the proper content.</p>



<p>Notice that ItemsView structure is the place where we declare and at the same time initialize the <code>mediaItems</code> object. Even though we need it here because it will act as the datasource for a List view that we&#x2019;ll add next, there&#x2019;s also another type where it&#x2019;s necessary as well; the PhotoPicker structure!</p>



<p>Open the PhotoPicker.swift file, and at the beginning of the PhotoPicker structure declare the next property:</p>



<pre class="wp-block-code"><code>struct PhotoPicker: UIViewControllerRepresentable {
    @ObservedObject var mediaItems: PickedMediaItems

    ...
}</code></pre>



<p>Here we declare the exact same property (we could have used a different name if we wanted to) marked with the @ObservedObject property wrapper too, but there&#x2019;s a difference; we do not initialize it!</p>



<p>Instead, we will pass the <code>mediaItems</code> object we created in the ItemsView right upon the initialization of the PhotoPicker object. To do that, go back to the ItemsView.swift and update it according to the next snippet, inside the sheet&#x2019;s content closure:</p>



<pre class="wp-block-code"><code>.sheet(isPresented: $showSheet, content: {
    PhotoPicker(mediaItems: mediaItems) { didSelectItem in
        // Handle didSelectItems value here...
        showSheet = false
    }
})</code></pre>



<p>From now on, whenever a media item will be added to the <code>items</code> array of the <code>mediaItems</code> property, ItemsView will be notified about that and it will redraw its contents in order to display the new item. Of course, we have to make a few additions to the ItemsView in order for that to happen, but we&#x2019;ll get to that soon.</p>



<h2 class="wp-block-heading">Getting A Photo From Picker Results</h2>



<p>In the <code>picker(_:didFinishPicking:)</code> delegate method of the PHPickerViewControllerDelegate we saw that selected items in the picker are represented as a collection of PHPickerResult objects. Each one of them contains a property called <code>itemProvider</code>, which is an instance of the NSItemProvider class. Citing the definition from Apple docs:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>NSItemProvider: An item provider for conveying data or a file between processes during drag and drop or copy/paste activities, or from a host app to an app extension.</p></blockquote>



<p>In the introduction of this post I said that PHPicker runs on a different process out of the app. When a user selects an item to import, <em>that item is transferred from that process to our own app wrapped into an item provider object</em>.</p>



<p>Having that in mind, let&#x2019;s go to the PhotoPicker.swift file and in the Coordinator class, where we are going to implement the following method:</p>



<pre class="wp-block-code"><code>private func getPhoto(from itemProvider: NSItemProvider) {

}</code></pre>



<p>This one will be extracting the photo from the given item provider, and on success, it will be storing it to a new PhotoPickerModel object, which in turn will be appended to the <code>items</code> array of the PhotoPicker&#x2019;s <code>mediaItems</code> property. Notice that we declare it as private; it&#x2019;s meaningful for the Coordinator class only, and there is no reason to make it visible out of it.</p>



<p>Since we want to get a photo, the first step in the method is to check if we can actually load an image object from the item provider. This is done as follows:</p>



<pre class="wp-block-code"><code>if itemProvider.canLoadObject(ofClass: UIImage.self) {

}</code></pre>



<p>The above method returns true or false, depending on whether the item provider can load an image object. Notice the <code>UIImage.self</code> argument; with that we tell to the method that we are interested in the UIImage type.</p>



<p>Supposing that the above returns true, our next move is to load the image from the item provider. This is possible in a similar way as above, but using a different method this time:</p>



<pre class="wp-block-code"><code>itemProvider.loadObject(ofClass: UIImage.self) { object, error in

}</code></pre>



<p>This method works asynchronously, and on completion it will bring back either the loaded object (a UIImage object in this case), or an error if occurred, as parameter values in the completion handler.</p>



<p>Before doing anything else, we have to check if the error is nil or not. In this tutorial we won&#x2019;t do any specific error handling, we&#x2019;ll simply print the error description. But in a real app, you&#x2019;d probably want to perform a more appropriate action in such case.</p>



<pre class="wp-block-code"><code>if let error = error {
    print(error.localizedDescription)
}</code></pre>



<p>If there&#x2019;s not an error, then most probably the <code>object</code> contains the image we are looking for. But in order to get it, we have to cast to the UIImage type; <code>object</code> is a <em>NSItemProviderReading</em> value:</p>



<pre class="wp-block-code"><code>if let image = object as? UIImage {

}</code></pre>



<p>If casting and unwrapping at the same time the optional <code>object</code> to the <code>image</code> constant succeeds, then we can eventually store the loaded image to a new PhotoPickerModel instance. This is what we&#x2019;ll append to the <code>items</code> array of the PhotoPicker&#x2019;s <code>mediaItem</code> property afterwards. Note that this is a task that has to take place on the <em>main thread</em> of the app! We are just about to trigger changes to a @Published property (the <code>items</code> array), and that should always happen to the main thread.</p>



<pre class="wp-block-code"><code>DispatchQueue.main.async {
    self.photoPicker.mediaItems.append(item: PhotoPickerModel(with: image))
}</code></pre>



<p>The new PhotoPickerModel is created with the <code>PhotoPickerModel(with: image)</code> part using the first custom initializer we implemented, and it&#x2019;s given as an argument to the <code>append(item:)</code> method. This one appends it to the <code>items</code> array of the <code>mediaItems</code> property.</p>



<p>Our method is ready, so let&#x2019;s see how it looks complete:</p>



<pre class="wp-block-code"><code>private func getPhoto(from itemProvider: NSItemProvider) {
    if itemProvider.canLoadObject(ofClass: UIImage.self) {
        itemProvider.loadObject(ofClass: UIImage.self) { object, error in
            if let error = error {
                print(error.localizedDescription)
            }

            if let image = object as? UIImage {
                DispatchQueue.main.async {
                    self.photoPicker.mediaItems.append(item: PhotoPickerModel(with: image))
                }
            }
        }
    }
}</code></pre>



<p>However, we are not done yet; we still don&#x2019;t make any use of the above method. The place to call it is the <code>picker(_:didFinishPicking:)</code> delegate method in the Coordinator class. Before adding a few bits of new code there, remember that we configured our picker so it&#x2019;s possible to select one photo only. That means that in the <code>picker(_:didFinishPicking:)</code> we&#x2019;ll take the item provider of the first result, and then we&#x2019;ll call the <code>getPhoto(from:)</code> providing the item provider as argument.</p>



<p>Here&#x2019;s how the <code>picker(_:didFinishPicking:)</code> must be updated with what I just said:</p>



<pre class="wp-block-code"><code>func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    ...

    let itemProvider = results[0].itemProvider
    self.getPhoto(from: itemProvider)
}</code></pre>



<h2 class="wp-block-heading">Displaying Photos</h2>



<p>With the PhotoPicker type capable of fetching selected photos, let&#x2019;s head to the ItemsView.swift file. Here we&#x2019;ll do the necessary preparations, so photos to be displayed after they have been selected in the picker.</p>



<p>I mentioned a few times up until now that we are going to use a List view in order to show multiple selected media items. That List does not exist yet, and that&#x2019;s what we&#x2019;ll do as a first step here; to create it.</p>



<p>Right now in the ItemsView body you will find an empty view (<code>EmptyView</code>), which acts as a placeholder until we have something to show. That time has come, so replace the following line:</p>



<pre class="wp-block-code"><code>EmptyView()</code></pre>



<p>with the following List initialization:</p>



<pre class="wp-block-code"><code>List(mediaItems.items, id: \.id) { item in

}</code></pre>



<p>The first argument in the List is a collection of items that will be used as the datasource by the views that we&#x2019;ll add to the List. The second argument is the <em>keypath</em> to the id value of each item in the collection (<code>\.id</code>). That is the <code>id</code> property declared in the PhotoPickerModel structure. The third argument is the closure where we&#x2019;ll add all necessary views in order to display photos, videos, and live photos. The List works by making iterations, and the <code>item</code> value in the closure represents the currently accessed item object in the <code>items</code> collection.</p>



<p>Since we want to display photos, we are going to use an Image view for that purpose. We&#x2019;ll put that inside the List&#x2019;s closure:</p>



<pre class="wp-block-code"><code>List(mediaItems.items, id: \.id) { item in
    Image(uiImage: item.photo ?? UIImage())
}</code></pre>



<p>Two things to notice here; first, we are initializing an Image view passing a UIImage as an argument. That&#x2019;s how we keep photos stored in the PhotoPickerModel. Second, in case the <code>photo</code> property of the item is nil, then we just provide an empty UIImage object.</p>



<p>Even though the above will show the photo that&#x2019;s saved in the item, it won&#x2019;t do that properly; if you would run the app now, you would have seen that the photo does not fit the Image view size. To change that, we&#x2019;ll set a specific <em>aspect ratio</em> value with the <code>aspectRatio(contentMode:)</code> view modifier. However, in order for that to have a real effect, it&#x2019;s necessary to use prior to it the <code>resizable()</code> modifier, so the Image view can resize its contents:</p>



<pre class="wp-block-code"><code>List(mediaItems.items, id: \.id) { item in
    Image(uiImage: item.photo ?? UIImage())
        .resizable()
        .aspectRatio(contentMode: .fit)
}</code></pre>



<p>The snippet above is the only modification we had to do in ItemsView. All the rest will happen automatically, as the view will redraw its contents once a photo has been stored to the <code>items</code> collection of the PickedMediaItems instance.</p>



<p>Run the app again now, and tap on the plus button to select and import a photo. You can do that multiple times; all of them will be displayed in the List view we just defined.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="553" height="1024" src="https://www.appcoda.com/content/images/wordpress/2021/01/t79_2_listed_photos-553x1024.png" alt="The Complete Guide to PHPicker API in iOS 14" class="wp-image-19014" srcset="https://www.appcoda.com/content/images/wordpress/2021/01/t79_2_listed_photos-553x1024.png 553w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_2_listed_photos-162x300.png 162w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_2_listed_photos-200x370.png 200w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_2_listed_photos-400x740.png 400w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_2_listed_photos-50x93.png 50w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_2_listed_photos.png 568w" sizes="(max-width: 553px) 100vw, 553px"></figure>



<h2 class="wp-block-heading">Picking Multiple Photos</h2>



<p>Now that we have managed to pick and present a single photo, let&#x2019;s continue to changing that and let&#x2019;s allow multiple photo picking. The place to start working for that is the PhotoPicker type, so open the PhotoPicker.swift file to edit it.</p>



<p>In the <code>makeUIViewController(context:)</code> method there is a line where we set the maximum selection limit:</p>



<pre class="wp-block-code"><code>config.selectionLimit = 1</code></pre>



<p>To allow picking unlimited items, set the <code>selectionLimit</code> to zero:</p>



<pre class="wp-block-code"><code>config.selectionLimit = 0</code></pre>



<p>You can also set a specific number if you want to have a limit higher than 1 but not unlimited.</p>



<p>Next stop is the <code>picker(_:didFinishPicking:)</code> delegate method inside the same file. Currently we are accessing the item provider of the first result only, and then we provide it to the <code>getPhoto(from:)</code> method.</p>



<p>Having changed the number of items items that can be selected, that implementation will not give us back all selected photos. To change that, first spot the following two lines:</p>



<pre class="wp-block-code"><code>let itemProvider = results[0].itemProvider
self.getPhoto(from: itemProvider)</code></pre>



<p>Once you find them, move them inside a loop as shown here:</p>



<pre class="wp-block-code"><code>for result in results {
    let itemProvider = results[0].itemProvider
    self.getPhoto(from: itemProvider)
}</code></pre>



<p>That <code>for</code> loop will go through all returned results, and process all photos. There is one last change to do; replace the first line in the loop that contains the <code>results[0]</code> with this:</p>



<pre class="wp-block-code"><code>let itemProvider = result.itemProvider</code></pre>



<p>By running the app now you will find out that it&#x2019;s possible to select and import multiple photos at once.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="553" height="1024" src="https://www.appcoda.com/content/images/wordpress/2021/01/t79_3_multi_select-553x1024.png" alt="The Complete Guide to PHPicker API in iOS 14" class="wp-image-19015" srcset="https://www.appcoda.com/content/images/wordpress/2021/01/t79_3_multi_select-553x1024.png 553w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_3_multi_select-162x300.png 162w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_3_multi_select-200x370.png 200w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_3_multi_select-400x740.png 400w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_3_multi_select-50x93.png 50w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_3_multi_select.png 568w" sizes="(max-width: 553px) 100vw, 553px"></figure>



<h2 class="wp-block-heading">Importing Videos</h2>



<p>The solution we implemented in the <code>getPhoto(from:)</code> method inside the Coordinator class of the PhotoPicker type works for photos, and with slight modifications is going to work for live photos too. But when it comes to videos, the approach we must follow is totally different.</p>



<p>Unlike photos, there is not a single object we can load from the item provider; and that makes sense if you think about it. It&#x2019;s not possible to load hundreds of megabytes of data to memory just for a single video. Videos have to be loaded from files.</p>



<p>And that&#x2019;s exactly what we&#x2019;ll do; we are going to deal with files.</p>



<p>Thankfully, NSItemProvider class has more APIs available to use, and one of them allows to get the data of a selected item as a file. However, there is something important to know here; the item provider creates a <em>temporary file</em> for every video we want to get to the &#x201C;tmp&#x201D; folder of the app, and then deletes it automatically after a while. It&#x2019;s our duty to copy that file to a location where it can live for a longer time, such as the documents or the caches directory of the app.</p>



<p>So, here we are going to implement another method in the Coordinator class, which will be responsible for getting a video from an item provider, and copying it to the documents directory of our application. Let&#x2019;s define it:</p>



<pre class="wp-block-code"><code>private func getVideo(from itemProvider: NSItemProvider, typeIdentifier: String) {

}</code></pre>



<p>The first argument is the item provider object which will provide us with the video file. The second argument is something that we meet for first time in this tutorial, but meant to play an important role here. It&#x2019;s the <em>uniform type identifier (UTI)</em> of the file we want to fetch.</p>



<p><strong>Note:</strong> In a nutshell, a UTI is a string value with a special syntax that allows to uniquely identify the kind of data in files, data types, etc, and it was defined by Apple. I would recommend to read <a href="https://developer.apple.com/documentation/uniformtypeidentifiers/?ref=appcoda.com">here</a> and <a href="https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_intro/understand_utis_intro.html?ref=appcoda.com">here</a> for more information from the official documentation.</p>



<p>To get an idea, the string &#x201C;public.png&#x201D; is the type identifier for PNG images. A type identifier can inherit from other types as well; for example, &#x201C;public.png&#x201D; inherits from &#x201C;public.image&#x201D;. Keep that information in mind, we&#x2019;ll need it soon.</p>



<p>How we&#x2019;ll get the type identifier that we need to provide in this new method is something that we will bother with later. Now, let&#x2019;s start adding some code to it.</p>



<p>The first and quite important move is to actually request from the item provider to give us the file representation of the selected video. This is done as shown right below, and see that we provide the type identifier as an argument:</p>



<pre class="wp-block-code"><code>itemProvider.loadFileRepresentation(forTypeIdentifier: typeIdentifier) { url, error in

}</code></pre>



<p>The method is executed asynchronously, and in its completion handler we are going to deal with the video file. The <code>url</code> parameter is pointing to the temporary file that the item provider created for us. Of course, chances for something to go wrong always exist, so the <code>error</code> object is there to let us know what error occurred, if any.</p>



<p>Just like we did in the <code>getPhoto(from:)</code> method, we&#x2019;ll continue by examining whether <code>error</code> is nil or not. If it&#x2019;s not, we&#x2019;ll simply print the error message, but do something more useful than that in your apps:</p>



<pre class="wp-block-code"><code>if let error = error {
    print(error.localizedDescription)
}</code></pre>



<p>In case where <code>error</code> is nil and we can proceed, then the first we&#x2019;ll do is to unwrap the <code>url</code> object; it&#x2019;s an optional value, and we must be sure that it&#x2019;s not nil:</p>



<pre class="wp-block-code"><code>guard let url = url else { return }</code></pre>



<p>If for some reason it&#x2019;s nil, and at the same time the error is nil, then there&#x2019;s nothing else we can do. We simply return from the method.</p>



<p>Supposing that <code>url</code> is unwrapped properly, then our next task is to copy the video file from the temporary URL to the documents directory of the app. Note that this the directory of my choice for the purposes of the tutorial, you can use caches directory instead.</p>



<p>Before we perform the actual copy operation, it&#x2019;s necessary to construct the target URL. This will be composed by two parts:</p>



<ol><li>The URL to the documents directory.</li><li>The <em>last path component</em> of the source directory, meaning the file name and any potential extension it might have.</li></ol>



<p>Let&#x2019;s get the URL to the documents directory first:</p>



<pre class="wp-block-code"><code>let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first</code></pre>



<p>Getting the last path component from the source URL is as easy as that (don&#x2019;t copy the following, it&#x2019;s just a demo):</p>



<pre class="wp-block-code"><code>url.lastPathComponent</code></pre>



<p>To add it to the documents directory URL, we&#x2019;ll use the <code>appendingPathComponent()</code> method of the URL class, and eventually we&#x2019;ll build the target URL:</p>



<pre class="wp-block-code"><code>guard let targetURL = documentsDirectory?.appendingPathComponent(url.lastPathComponent) else { return }</code></pre>



<p>If the target URL has been constructed properly, and once we make sure that it&#x2019;s not nil by unwrapping it, then we can do the actual copy. First though, we&#x2019;ll check if a file with the similar path already exists or not to the target URL, and if so we&#x2019;ll delete it and then we&#x2019;ll copy.</p>



<p>Deleting and copying files are operations that can throw exceptions, and the proper way to treat them is by including them in a <code>do-catch</code> statement:</p>



<pre class="wp-block-code"><code>do {

} catch {
    print(error.localizedDescription)
}</code></pre>



<p>Once again, if something bad happens, we just print the error description.</p>



<p>Inside the <code>do</code> clause now, let&#x2019;s do the real work. We&#x2019;ll use the <em>FileManager</em> class to perform all file-related tasks. We&#x2019;ll start by checking if a similarly named file exists, and we&#x2019;ll delete it, if it does:</p>



<pre class="wp-block-code"><code>if FileManager.default.fileExists(atPath: targetURL.path) {
    try FileManager.default.removeItem(at: targetURL)
}</code></pre>



<p><code>fileExists(atPath:)</code> and <code>removeItem(at:)</code> are the FileManager methods that do the job. Notice that FileManager is a Singleton class, and we access everything through the <code>default</code> shared object. Also, two more noteworthy things:</p>



<ol><li><code>removeItem(at:)</code> method can throw an exception, so it&#x2019;s marked with the <code>try</code> keyword.</li><li>The parameter of the <code>fileExists(atPath:)</code> should be a string value, but the parameter of the <code>removeItem(at:)</code> should be a URL object. That&#x2019;s why in the first case we access the <code>path</code> property of the target URL; it returns it as a string value.</li></ol>



<p>Next, we can perform the actual copy:</p>



<pre class="wp-block-code"><code>try FileManager.default.copyItem(at: url, to: targetURL)</code></pre>



<p>We mark this method with the <code>try</code> keyword too, as if the file copy fails it will throw an exception. The first argument we provide it with is the source URL, and the second is the destination URL.</p>



<p>If things go well and we get no exception up to this point, then we can go ahead and create a new PhotoPickerModel object in order to store the target URL; the place where we are going to find the selected video in order to display it in the app. Rememeber that we do that on the main thread of the app:</p>



<pre class="wp-block-code"><code>DispatchQueue.main.async {
    self.photoPicker.mediaItems.append(item: PhotoPickerModel(with: targetURL))
}</code></pre>



<p>The method is now complete:</p>



<pre class="wp-block-code"><code>private func getVideo(from itemProvider: NSItemProvider, typeIdentifier: String) {
    itemProvider.loadFileRepresentation(forTypeIdentifier: typeIdentifier) { url, error in
        if let error = error {
            print(error.localizedDescription)
        }

        guard let url = url else { return }

        let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
        guard let targetURL = documentsDirectory?.appendingPathComponent(url.lastPathComponent) else { return }

        do {
            if FileManager.default.fileExists(atPath: targetURL.path) {
                try FileManager.default.removeItem(at: targetURL)
            }

            try FileManager.default.copyItem(at: url, to: targetURL)

            DispatchQueue.main.async {
                self.photoPicker.mediaItems.append(item: PhotoPickerModel(with: targetURL))
            }
        } catch {
            print(error.localizedDescription)
        }
    }
}</code></pre>



<h3 class="wp-block-heading">Updating The Picker Delegate Method</h3>



<p>As we did with the <code>getPhoto(from:)</code> method, we are going to call <code>getVideo(from:typeIdentifier:)</code> in the picker&#x2019;s delegate method too. But in order to do that, we must come up with a solution about two things:</p>



<ul><li>How to get the type identifier necessary for the method we just implemented.</li><li>How to distinguish the media type so we know which method to call; the one for getting the photo, or the one for getting the video.</li></ul>



<p>In fact, taking care of the first will help answer the second bullet above as well! We will be based on the type identifier of the data that each item provider carries over; depending on the parent type that conforms to, we&#x2019;ll decide whether it&#x2019;s a photo or a video. Photo-related types conform to &#x201C;public.image&#x201D; type, and video-related types conform to &#x201C;public.movie&#x201D; type.</p>



<p>But first things first. To get the type identifier of the data that an item provider contains, we have to access a property called <code>registeredTypeIdentifiers</code>. Its value is an array of strings representing all types that data relates to. The first object of that array is what we actually need:</p>



<pre class="wp-block-code"><code>let typeIdentifier = itemProvider.registeredTypeIdentifiers.first</code></pre>



<p>To manage to determine what parent type the identifier conforms to, it&#x2019;s necessary to create an object of the <em>UTType</em> type, also new in iOS 14:</p>



<pre class="wp-block-code"><code>let utType = UTType(typeIdentifier)</code></pre>



<p>Let&#x2019;s combine the above two in one single <code>guard</code> statement, as both of them can give us a nil value:</p>



<pre class="wp-block-code"><code>guard let typeIdentifier = itemProvider.registeredTypeIdentifiers.first,
      let utType = UTType(typeIdentifier)
else { continue }</code></pre>



<p>The above must go inside the <code>for</code> loop in the <code>picker(_:didFinishPicking:)</code> method:</p>



<pre class="wp-block-code"><code>for result in results {
    let itemProvider = result.itemProvider

    guard let typeIdentifier = itemProvider.registeredTypeIdentifiers.first,
          let utType = UTType(typeIdentifier)
    else { continue }

}</code></pre>



<p>Note that the call to the <code>getPhoto(from:)</code> method does not exist now in the above snippet. That&#x2019;s because we have to determine first if data on each item provider is an image or a video.</p>



<p>To achieve that, we will use a method of the UTType type, called <code>conforms(to:)</code>, in an <code>if</code> statement (still inside the <code>for</code> loop) as shown next:</p>



<pre class="wp-block-code"><code>if utType.conforms(to: .image) {

} else if utType.conforms(to: .movie) {

}</code></pre>



<p>The argument provided to the <code>conforms(to:)</code> is a UTType value indicating the parent type that we want to know if our type inherits from.</p>



<p>Now, depending on whether we are talking about an image or a video, we can call the appropriate custom method:</p>



<pre class="wp-block-code"><code>if utType.conforms(to: .image) {
    self.getPhoto(from: itemProvider)
} else if utType.conforms(to: .movie) {
    self.getVideo(from: itemProvider, typeIdentifier: typeIdentifier)
}</code></pre>



<p>Before we switch to the ItemsView in order to make it possible to playback videos, let&#x2019;s go to the <code>makeUIViewController(context:)</code> method of the PhotoPicker structure in order to allow picking videos as well. Find the next line:</p>



<pre class="wp-block-code"><code>config.filter = .images</code></pre>



<p>Now, replace it with this:</p>



<pre class="wp-block-code"><code>config.filter = .any(of: [.images, .videos])</code></pre>



<p>The <code>any(of:)</code> method is a PHPickerFilter API that let us provide an array of PHPickerFilter values matching to media items we want to make available in the picker; exactly what is shown above.</p>



<h2 class="wp-block-heading">Playing Back Videos</h2>



<p>At the moment, the ItemsView is capable of presenting only photos. But now that we are able to import videos as well, that&#x2019;s something we are going to change. To determine what kind of media should be displayed, we are going to be based on the <code>mediaType</code> property of each PhotoPickerModel item in the List view.</p>



<p>To get started with the view updates, first open the ItemsView.swift file. Then, inside the List view add the following (you can remove for a while the Image view with its modifiers):</p>



<pre class="wp-block-code"><code>List(mediaItems.items, id: \.id) { item in
    if item.mediaType == .photo {

    } else if item.mediaType == .video {

    }
}</code></pre>



<p>The conditional display of views is the first reason for the existence of the <code>mediaType</code> property. There is one more, but we&#x2019;ll talk about that in a while.</p>



<p>Now, in the first case where the media type indicates a photo, we can put back the Image view and its modifiers:</p>



<pre class="wp-block-code"><code>List(mediaItems.items, id: \.id) { item in
    if item.mediaType == .photo {
        Image(uiImage: item.photo ?? UIImage())
            .resizable()
            .aspectRatio(contentMode: .fit)
    } else if item.mediaType == .video {

    }
}</code></pre>



<p>In the <code>else if</code> clause where the media type regards a video, we are going to add a view that is capable of playing back videos. As you will see right next, video playback is an extremely simple task in iOS 14.</p>



<p>But first, we need to import another framework to the view; go to the beginning of the file, and right after the SwiftUI import statement add the following:</p>



<pre class="wp-block-code"><code>import AVKit</code></pre>



<p>The AVKit framework will allow us to access the <code>VideoPlayer</code> structure; a SwiftUI view that allows to playback videos.</p>



<p>The argument we have to provide with a VideoPlayer view upon initialization is an <em>AVPlayer</em> instance:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>An object that provides the interface to control the player&#x2019;s transport behavior.</p></blockquote>



<p>An AVPlayer object in turn is initialized with a URL pointing to the location of a video file; exactly what we keep stored in our model for videos!</p>



<p>So, after all that, let&#x2019;s see how everything is done in code. At first we&#x2019;ll make sure that the URL to a video file is not nil; in case it is, we&#x2019;ll add an EmptyView:</p>



<pre class="wp-block-code"><code>if let url = item.url {

} else { EmptyView() }</code></pre>



<p>In the <code>if let</code> clause, we&#x2019;ll create a new VideoPlayer view, passing an AVPlayer object as argument:</p>



<pre class="wp-block-code"><code>VideoPlayer(player: AVPlayer(url: url))</code></pre>



<p>Lastly, to avoid strange effects when media will be displayed in the List, let&#x2019;s set a minimum height to the video player:</p>



<pre class="wp-block-code"><code>VideoPlayer(player: AVPlayer(url: url))
    .frame(minHeight: 200)</code></pre>



<p>Here&#x2019;s the List view now:</p>



<pre class="wp-block-code"><code>List(mediaItems.items, id: \.id) { item in
    if item.mediaType == .photo {
        Image(uiImage: item.photo ?? UIImage())
            .resizable()
            .aspectRatio(contentMode: .fit)
    } else if item.mediaType == .video {
        if let url = item.url {
            VideoPlayer(player: AVPlayer(url: url))
                .frame(minHeight: 200)
        } else { EmptyView() }
    }
}</code></pre>



<p>Now we can go ahead and pick both photos and videos. When you add a video, you&#x2019;ll see that you can start and stop its playback using default controls provided by iOS.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="553" height="1024" src="https://www.appcoda.com/content/images/wordpress/2021/01/t79_4_import_video-553x1024.png" alt="The Complete Guide to PHPicker API in iOS 14" class="wp-image-19016" srcset="https://www.appcoda.com/content/images/wordpress/2021/01/t79_4_import_video-553x1024.png 553w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_4_import_video-162x300.png 162w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_4_import_video-200x370.png 200w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_4_import_video-400x740.png 400w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_4_import_video-50x93.png 50w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_4_import_video.png 568w" sizes="(max-width: 553px) 100vw, 553px"></figure>



<h2 class="wp-block-heading">Importing Live Photos</h2>



<p>Having dealt with photos and videos, it&#x2019;s about time to discuss about how to import live photos to the app using the PHPicker view controller. As you will see in this part, there are many similarities to handling photos, and that will allow us to use code we have already implemented.</p>



<p>To get started, open the PhotoPicker.swift file and go to the <code>getPhoto(from:)</code> method in the Coordinator class. Unlike videos but like photos, live photos can be loaded as objects from an item providers. Therefore, the <code>loadObject(ofClass:)</code> method can be used in this case too, with the only difference being the type of object we want to load.</p>



<p>In fact, everything we&#x2019;ve done in <code>getPhoto(from:)</code> method will be kept almost as is. What needs to be added as a first step, is a way to determine whether the object that is about to be loaded should be a normal photo or a live photo. And to do that, we&#x2019;ll start with the method&#x2019;s signature. We will add a new parameter value, a Boolean value, which will be indicating whether the item provider contains a live photo or not. Update the method as follows:</p>



<pre class="wp-block-code"><code>private func getPhoto(from itemProvider: NSItemProvider, isLivePhoto: Bool) {
    ...
}</code></pre>



<p>When <code>isLivePhoto</code> is false, then the UIImage type is what we will provide to both <code>canLoadObject(ofClass:)</code> and <code>loadObject(ofClass:)</code> methods. But when it&#x2019;s true, then we have to specify a different type. For live photos, that type is <strong>PHLivePhoto</strong>.</p>



<p>Based on that thinking, let&#x2019;s add the following statement as the first line in the <code>getPhoto(from:isLivePhoto:)</code> method. It declares a constant called <code>objectType</code> as a NSItemProviderReading type; the data type that both item provider methods expect. In case of a normal photo, it gets the type of the UIImage (<code>UIImage.self</code>), and in case of a live photo, it gets the type of the PHLivePhoto (<code>PHLivePhoto.self</code>):</p>



<pre class="wp-block-code"><code>private func getPhoto(from itemProvider: NSItemProvider, isLivePhoto: Bool) {
    let objectType: NSItemProviderReading.Type = !isLivePhoto ? UIImage.self : PHLivePhoto.self

    ...
}</code></pre>



<p>Now we can update the arguments we provide to both <code>canLoadObject(ofClass:)</code> and <code>loadObject(ofClass:)</code> methods:</p>



<pre class="wp-block-code"><code>if itemProvider.canLoadObject(ofClass: objectType) {
    itemProvider.loadObject(ofClass: objectType) { object, error in
        ...
    }
}    </code></pre>



<p>A few lines below, we have the code that converts the loaded object to a UIImage and then stores it to a new PhotoPickerModel object. We have to move that part of code inside an <code>if-else</code> condition which will be checking the value of the <code>isLivePhoto</code> parameter value:</p>



<pre class="wp-block-code"><code>if !isLivePhoto {
    if let image = object as? UIImage {
        DispatchQueue.main.async {
            self.photoPicker.mediaItems.append(item: PhotoPickerModel(with: image))
        }
    }
} else {

}</code></pre>



<p>In the <code>else</code> clause we&#x2019;ll do exactly what we do in the case of the image object; except that this time we&#x2019;ll cast to a PHLivePhoto object:</p>



<pre class="wp-block-code"><code>if let livePhoto = object as? PHLivePhoto {
    DispatchQueue.main.async {
        self.photoPicker.mediaItems.append(item: PhotoPickerModel(with: livePhoto))
    }
}</code></pre>



<p>These are the necessary changes to this method, and here&#x2019;s how it finally looks:</p>



<pre class="wp-block-code"><code>private func getPhoto(from itemProvider: NSItemProvider, isLivePhoto: Bool) {
    let objectType: NSItemProviderReading.Type = !isLivePhoto ? UIImage.self : PHLivePhoto.self

    if itemProvider.canLoadObject(ofClass: objectType) {
        itemProvider.loadObject(ofClass: objectType) { object, error in
            if let error = error {
                print(error.localizedDescription)
            }

            if !isLivePhoto {
                if let image = object as? UIImage {
                    DispatchQueue.main.async {
                        self.photoPicker.mediaItems.append(item: PhotoPickerModel(with: image))
                    }
                }
            } else {
                if let livePhoto = object as? PHLivePhoto {
                    DispatchQueue.main.async {
                        self.photoPicker.mediaItems.append(item: PhotoPickerModel(with: livePhoto))
                    }
                }
            }

        }
    }
}</code></pre>



<p>Now, let&#x2019;s update the <code>picker(_:didFinishPicking:)</code> delegate method for one last time. From a previous part, we have a condition there that checks the parent type of the type identifier taken from the item provider:</p>



<pre class="wp-block-code"><code>if utType.conforms(to: .image) {
    self.getPhoto(from: itemProvider)
} else if utType.conforms(to: .movie) {
    self.getVideo(from: itemProvider, typeIdentifier: typeIdentifier)
}</code></pre>



<p>We are going to append an <code>else</code> case to the condition, which will match to live photos. In it we&#x2019;ll call the <code>getPhoto(from:isLivePhoto:)</code> method, passing true as the second argument:</p>



<pre class="wp-block-code"><code>if utType.conforms(to: .image) {
    ...
} else if utType.conforms(to: .movie) {
    ...
} else {
    self.getPhoto(from: itemProvider, isLivePhoto: true)
}</code></pre>



<p>Then, we are going to fix the call to <code>getPhoto(from:)</code> method in the <code>if</code> clause. That method now expects for one more parameter value, which in that case will be false, indicating a normal photo:</p>



<pre class="wp-block-code"><code>if utType.conforms(to: .image) {
    self.getPhoto(from: itemProvider, isLivePhoto: false)
} else if utType.conforms(to: .movie) {
    self.getVideo(from: itemProvider, typeIdentifier: typeIdentifier)
} else {
    self.getPhoto(from: itemProvider, isLivePhoto: true)
}</code></pre>



<p>Changes have finished in that method too. Lastly, let&#x2019;s pay one more visit to the <code>makeUIViewController(context:)</code> method of the PhotoPicker structure, and allow to select live photos in the picker along with the other media types. Replace the following line:</p>



<pre class="wp-block-code"><code>config.filter = .any(of: [.images, .videos])</code></pre>



<p>with this one:</p>



<pre class="wp-block-code"><code>config.filter = .any(of: [.images, .videos, .livePhotos])</code></pre>



<p>And with that, our work in the PhotoPicker.swift file is now finished.</p>



<h2 class="wp-block-heading">Previewing Live Photos</h2>



<p>A live photo is a special category of media, and in order to preview such a photo properly, PhotosUI framework provides a specific view for that; it&#x2019;s called <strong>PHLivePhotoView</strong>. That&#x2019;s the good news, because there&#x2019;s bad news as well when working in SwiftUI. PHLivePhotoView is a UIView, meaning a UIKit view, and it cannot be used natively in SwiftUI.</p>



<p>To workaround this issue, it&#x2019;s necessary to create a new custom type, a structure, that will be conforming to the <em>UIViewRepresentable</em> protocol. In analogy to UIViewControllerRepresentable and view controllers, UIViewRepresentable allows to bring UIKit <em>views</em> to SwiftUI.</p>



<p>The steps required to be followed in order to implement a UIViewRepresentable type are quite similar to those we already met in the PhotoPicker structure. We&#x2019;ll go through them by implementing a new type which we&#x2019;ll call <em>LivePhotoView</em>.</p>



<p>We&#x2019;ll do that in a separate file, the one that remains in the starter project and we haven&#x2019;t added code to yet; The LivePhotoView.swift, so open to edit it.</p>



<p>Start by replacing the Foundation framework with the usual two we added in other files too:</p>



<pre class="wp-block-code"><code>import SwiftUI
import PhotosUI</code></pre>



<p>Now, let&#x2019;s define our new type, the LivePhotoView, which will be conforming to the UIViewRepresentable protocol:</p>



<pre class="wp-block-code"><code>struct LivePhotoView: UIViewRepresentable {

}</code></pre>



<p>UIViewRepresentable has three requirements, similar to the UIViewControllerRepresentable:</p>



<ul><li>To specify the type of view that we are importing to SwiftUI.</li><li>To implement a method where we&#x2019;ll initialize, configure and return the view.</li><li>To implement one more method for updating the view.</li></ul>



<p>Let&#x2019;s add all those at once and specify the PHLivePhotoView as the one that our custom type will be handling:</p>



<pre class="wp-block-code"><code>struct LivePhotoView: UIViewRepresentable {
    typealias UIViewType = PHLivePhotoView

    func makeUIView(context: Context) -&gt; PHLivePhotoView {

    }

    func updateUIView(_ uiView: PHLivePhotoView, context: Context) {

    }
}</code></pre>



<p>The <code>updateUIView(_:context:)</code> method is required to exist, but adding code to it is optional. We are going to leave it empty, as there&#x2019;s nothing to update.</p>



<p>Before initializing a brand new PHLivePhotoView, let&#x2019;s declare the following property to LivePhotoView structure:</p>



<pre class="wp-block-code"><code>struct LivePhotoView: UIViewRepresentable {
    var livePhoto: PHLivePhoto

    ...
}</code></pre>



<p>This is going to be the actual live photo that we will be previewing.</p>



<p>Initializing a PHLivePhotoView instance hides no surprises; at first we create the instance, then we assign the live photo object, and finally we return it from the <code>makeUIView(context:)</code> method:</p>



<pre class="wp-block-code"><code>func makeUIView(context: Context) -&gt; PHLivePhotoView {
    let livePhotoView = PHLivePhotoView()
    livePhotoView.livePhoto = livePhoto
    return livePhotoView
}</code></pre>



<p>It&#x2019;s possible in a PHLivePhotoView to playback a part of the live photo&#x2019;s video, as a <em>hint</em> that this is a live and not a normal photo. If you want to see that happening, add the following line right before returning from the method above:</p>



<pre class="wp-block-code"><code>livePhotoView.startPlayback(with: .hint)</code></pre>



<p>There is also a delegate protocol called <em>PHLivePhotoViewDelegate</em>, and provides two delegate methods:</p>



<pre class="wp-block-code"><code>livePhotoView(_:willBeginPlaybackWith:)

livePhotoView(_:didEndPlaybackWith:)</code></pre>



<p>You can use them to be notified when the playback of a live photo is about to start, or it&#x2019;s finished respectively. We don&#x2019;t need them, so we won&#x2019;t implement them here. But be advised; in order to do that, you have to add a Coordinator class in LivePhotoView, exactly as we did in the PhotoPicker structure. Also, the coordinator will have to inherit from the <em>NSObject</em> class and adopt the <em>PHLivePhotoViewDelegate</em> protocol.</p>



<p>With the LivePhotoView type implemented at this point, let&#x2019;s head to the ItemsView.swift file to make use of it. Inside the List view we have a conditional presentation of views; we display an Image view for normal photos, and a VideoPlayer view for videos.</p>



<p>Now we are going to add an <code>else</code> clause to that condition, where we&#x2019;ll create a LivePhotoView instance. There, we&#x2019;ll pass the fetched live photo as argument, but after we&#x2019;ve made sure that it&#x2019;s not nil. If it is, once again we&#x2019;ll have an EmptyView:</p>



<pre class="wp-block-code"><code>List(mediaItems.items, id: \.id) { item in
    if item.mediaType == .photo {
        ...
    } else if item.mediaType == .video {
        ...
    } else {
        if let livePhoto = item.livePhoto {
            LivePhotoView(livePhoto: livePhoto)
                .frame(minHeight: 200)
        } else { EmptyView() }
    }
}</code></pre>



<p>See that once again we set a minimum height for the live photo view, like we did for the VideoPlayer view.</p>



<p>To test importing live photos, you will have to run the app in a real device and pick one or more of those from the library. If you have enabled the hint playback with the method I demonstrated previously, then you&#x2019;ll see the live photo playing back automatically. Regardless, just long press on any imported live photo and you&#x2019;ll preview it just like you do in Photos app!</p>



<h2 class="wp-block-heading">Deleting Media Items</h2>



<p>Before we reach to the end of our work in this post, it would be a good idea to make it possible to delete media items that have been imported to the app. By doing that, we&#x2019;ll enable the trash button that already exists in the starter project and it&#x2019;s not usable up until now. Also, this will make the demo app more complete.</p>



<p>We&#x2019;ll manage to delete items by performing three distinct steps. The first one is going to take place in the PhotoPickerModel.swift file, in the PhotoPickerModel structure. It&#x2019;s necessary to add a new method which:</p>



<ul><li>Will be setting nil to <code>photo</code> and <code>livePhoto</code> properties.</li><li>Will be deleting the video file using the stored URL, and then making the URL nil as well.</li></ul>



<p>All that will happen conditionally in a <code>switch</code> statement:</p>



<pre class="wp-block-code"><code>mutating func delete() {
    switch mediaType {
        case .photo: photo = nil
        case .livePhoto: livePhoto = nil
        case .video:
            guard let url = url else { return }
            try? FileManager.default.removeItem(at: url)
            self.url = nil
    }
}</code></pre>



<p>Notice that we mark the <code>delete()</code> method as mutating because it&#x2019;s causing changes to the properties of the structure. Also, to speed up the work, we use the <code>try?</code> keyword with the <code>removeItem(at:)</code> method without a <code>do-catch</code> statement.</p>



<p>Our next stop is the PickedMediaItems class; we&#x2019;ll add a method which will be calling the one that we just implemented for each item existing in the <code>items</code> array, and then will be emptying it:</p>



<pre class="wp-block-code"><code>func deleteAll() {
    for (index, _) in items.enumerated() {
        items[index].delete()
    }

    items.removeAll()
}</code></pre>



<p>Finally, the last step is to go to ItemsView.swift file, and update the action of the trash button in the <code>navigationBarItems</code> modifier:</p>



<pre class="wp-block-code"><code>.navigationBarItems(leading: Button(action: {
    mediaItems.deleteAll()
}, ...</code></pre>



<p>If you run the app now, all items you have imported to the app will be deleted by tapping on the trash button.</p>



<h2 class="wp-block-heading">Bonus Part &#x2013; Visually Distinguish Media Items</h2>



<p>This part is not a mandatory step in order to work with PHPicker and handle media items. The essential part of the work has already finished, but this is an additional step that will make the demo application a bit better, and might give you ideas for your own apps. So, reading it is optional.</p>



<p>The way the demo app is right now, makes it difficult to say what the type of each imported media item is simply by looking at it. There is a difference in videos, as there is the play button on top them, but what about normal and live photos? Unless we tap on them, we don&#x2019;t know their type.</p>



<p>To make it easy to distinguish each media item, we are going to add a small image on top of each displayed media item. Each media type will have a different image, but what makes it interesting is that we are not going to import any custom images to the project. We will use <em>SF Symbols</em> for that.</p>



<p><strong>Note:</strong> In case you haven&#x2019;t done that yet, I really recommend to <a href="https://developer.apple.com/sf-symbols/?ref=appcoda.com">download the SF Symbols app</a> from Apple.</p>



<p>To display an SF Symbol to an Image view as an image, the <code>Image(systemName:)</code> initializer must be used. The argument we need to pass to it, it&#x2019;s the name of the SF Symbol we want to use as a string value.</p>



<p>Since we have three different media types, we are going to create a small assistive method in the ItemsView structure which will be performing a simple task; it will return the name of the SF Symbol that should be used, depending on the <code>mediaItem</code> value of each item in the List view.</p>



<p>In the ItemsView.swift file, go right after the ItemsView&#x2019;s body, and add the following method:</p>



<pre class="wp-block-code"><code>fileprivate func getMediaImageName(using item: PhotoPickerModel) -&gt; String {
    switch item.mediaType {
        case .photo: return &quot;photo&quot;
        case .video: return &quot;video&quot;
        case .livePhoto: return &quot;livephoto&quot;
    }
}</code></pre>



<p>We are using a <code>switch</code> statement in order to return the proper SF Symbol name for each <code>mediaItem</code> possible value. The returned string values are not random; they have been taken from the SF Symbols app. Also, the above method is the second reason why <code>mediaType</code> property was necessary in the PhotoPickerModel type.</p>



<p>Now, in order to display an Image with an SF Symbol on top of each view that displays a media item, it&#x2019;s necessary to use a <em>ZStack</em>; such a stack piles up contained views on top of each other.</p>



<p>Inside the List view, add the following as the first thing in the closure:</p>



<pre class="wp-block-code"><code>List(mediaItems.items, id: \.id) { item in
    ZStack(alignment: .topLeading) {

    }
}</code></pre>



<p>The argument we provide to the <code>alignment</code> parameter of the ZStack is the desired position of the top-most view. That view will be the Image view with the SF Symbol, and it will be placed on the top-leading edge of the view that exists underneath.</p>



<p><strong>Note:</strong> Top-leading edge is the top-left side for LTR localizations, and top-right side for RTL localizations.</p>



<p>Next, inside the ZStack&#x2019;s closure we will add the conditional presentation of the views as is:</p>



<pre class="wp-block-code"><code>ZStack(alignment: .topLeading) {
    if item.mediaType == .photo {
        Image(uiImage: item.photo ?? UIImage())
            .resizable()
            .aspectRatio(contentMode: .fit)
    } else if item.mediaType == .video {
        if let url = item.url {
            VideoPlayer(player: AVPlayer(url: url))
                .frame(minHeight: 200)
        } else { EmptyView() }
    } else {
        if let livePhoto = item.livePhoto {
            LivePhotoView(livePhoto: livePhoto)
                .frame(minHeight: 200)
        } else { EmptyView() }
    }

    // Image view will go here...
}</code></pre>



<p>Even though we have several lines of code in the condition above, the final result will be the display of one view only. Right below that bunch of lines, exactly where I&#x2019;ve put the <code>// Image view will go here...</code> comment, we&#x2019;ll add the Image view:</p>



<pre class="wp-block-code"><code>Image(systemName: getMediaImageName(using: item))</code></pre>



<p>This is where the <code>getMediaImageName(using:)</code> method we implemented above is meant to be used. Even though that line will show the SF Symbol as an image, it would be nice to configure it a bit with view modifiers and make it look nice.</p>



<p>At first we&#x2019;ll make sure that the SF Symbol image will fit to the Image view size, so we&#x2019;ll add the next two modifiers:</p>



<pre class="wp-block-code"><code>.resizable()
.aspectRatio(contentMode: .fit)</code></pre>



<p>Then, we&#x2019;ll set a specific size for the Image view; the <code>resizable()</code> modifier we added above will help on that:</p>



<pre class="wp-block-code"><code>.frame(width: 24, height: 24)</code></pre>



<p>Also, we&#x2019;ll apply some padding around the image inside the Image view, and we&#x2019;ll set a semi-transparent background color; with that we ensure that the image will be visible on any background underneath the Image view:</p>



<pre class="wp-block-code"><code>.padding(4)
.background(Color.black.opacity(0.5))</code></pre>



<p>Finally, we&#x2019;ll set a foreground color to the displayed image in order to make sure that it will be looking properly in both light and dark color scheme:</p>



<pre class="wp-block-code"><code>.foregroundColor(.white)</code></pre>



<p>Eventually, this is how the List view looks after all the above:</p>



<pre class="wp-block-code"><code>List(mediaItems.items, id: \.id) { item in
    ZStack(alignment: .topLeading) {
        if item.mediaType == .photo {
            Image(uiImage: item.photo ?? UIImage())
                .resizable()
                .aspectRatio(contentMode: .fit)
        } else if item.mediaType == .video {
            if let url = item.url {
                VideoPlayer(player: AVPlayer(url: url))
                    .frame(minHeight: 200)
            } else { EmptyView() }
        } else {
            if let livePhoto = item.livePhoto {
                LivePhotoView(livePhoto: livePhoto)
                    .frame(minHeight: 200)
            } else { EmptyView() }
        }

        Image(systemName: getMediaImageName(using: item))
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 24, height: 24)
            .padding(4)
            .background(Color.black.opacity(0.5))
            .foregroundColor(.white)
    }
}</code></pre>



<p>If you run the app now you&#x2019;ll see the SF Symbols presented above each media item, indicating their type. If you run on a device, you&#x2019;ll see how live photos look too.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="553" height="1024" src="https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-1-553x1024.png" alt="The Complete Guide to PHPicker API in iOS 14" class="wp-image-19017" srcset="https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-1-553x1024.png 553w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-1-162x300.png 162w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-1-200x370.png 200w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-1-400x740.png 400w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-1-50x93.png 50w, https://www.appcoda.com/content/images/wordpress/2021/01/t79_5_images_on_items-1.png 568w" sizes="(max-width: 553px) 100vw, 553px"></figure>



<h2 class="wp-block-heading">Summary</h2>



<p>In an undeniably long post, we met the brand new PHPicker API in iOS 14, and how to use it in order to import photos, videos and live photos to your apps. You can now take what you learnt and did here, and use it straight in your projects. Or, feel free to modify whatever you find necessary and make it fit your needs. </p>



<p>Before closing, I&#x2019;d like to give you a word of caution. Imported normal and live photos are loaded to memory at full size, and you can easily run out of memory if you import many of them. That will lead to unexpected terminations of your app, which is a really bad thing to happen on users&#x2019; hands. You have two options to counterattack that; either to resize imported images before displaying them (as an intermediate step after fetching them), or, even better, to use the method we followed for videos; to copy files instead of loading objects. That might not be that easy for live photos, as they require a lot of additional work in order to break and put back together the image and the video, but keep it in mind anyway. </p>



<p>For a small number of imported photos, you&#x2019;ll have no problem at all. With that said, I hope you enjoyed this tutorial, and that you learnt something new here! Take care!</p>



<p>You can <a href="https://github.com/appcoda/PHPickerDemo?ref=appcoda.com" class="rank-math-link">download the complete project</a> on GitHub.</p>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[Testing In-App Purchases Using StoreKit in Xcode]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>WWDC20 finished almost two months ago, but still we are all talking about the new frameworks, APIs, and improvements announced this year. Among all those there&#x2019;s something that is going to have a strong impact to the way we work when implementing in-app purchases in our apps. That</p>]]></description><link>https://www.appcoda.com/storekit-testing/</link><guid isPermaLink="false">66612a0f166d3c03cf0114da</guid><category><![CDATA[iOS Programming]]></category><dc:creator><![CDATA[Gabriel Theodoropoulos]]></dc:creator><pubDate>Fri, 21 Aug 2020 22:53:06 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2020/08/b4ndbw2r_q8.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2020/08/b4ndbw2r_q8.jpg" alt="Testing In-App Purchases Using StoreKit in Xcode"><p>WWDC20 finished almost two months ago, but still we are all talking about the new frameworks, APIs, and improvements announced this year. Among all those there&#x2019;s something that is going to have a strong impact to the way we work when implementing in-app purchases in our apps. That is the brand new capability of testing StoreKit locally in <a href="https://www.appcoda.com/xcode-12-swift-53/" class="rank-math-link">Xcode 12</a>.</p>



<p>Up until now one had to stop the development workflow and visit the App Store Connect in order to create the necessary in-app purchase records and at least one sandbox user so testing is possible. After having gone through all required steps that we had described in a <a href="https://www.appcoda.com/in-app-purchases-guide/">previous tutorial</a>, developer could continue writing the in-app purchases related code. Obviously a disturbing yet unavoidable change of mindset like that is always enough to slow the development process down. In addition to that, subsequent visits to the App Store Connect would also be necessary most of the times in order to create additional test users.</p>



<p>Thankfully, that slow situation might belong to the past starting from Xcode 12 with the <a href="https://developer.apple.com/documentation/storekit?ref=appcoda.com" class="rank-math-link">StoreKit</a> local testing! Not only it&#x2019;s not necessary to stop the development workflow in order to visit the App Store Connect, but implementing and debugging IAPs can now be done at a blazing speed locally, simply using the Xcode and the Simulator. Developers can focus more on code implementation and make in-app purchases work perfectly, without any concern about in-app purchases records or test users until all implementation is finished. An additional benefit of StoreKit local testing is that it works offline, so in-app purchases can be implemented and tested even when there&#x2019;s no Internet access available.</p>



<p>During the next parts of this post you&#x2019;ll probably find various reasons why testing StoreKit locally is great. However, what makes it really awesome is the fact that it will eventually make in-app purchases integration a less painful task, and testing implemented logic and any related user interface a much, much faster process.</p>



<p>Before we move on to the next part, there&#x2019;s one more noteworthy fact; there&#x2019;s a brand new framework called <code>StoreKitTest</code> which allows to write unit and UI tests, and therefore automate in-app purchases testing. Isn&#x2019;t that really amazing?</p>



<h2 class="wp-block-heading">About The Demo App</h2>



<p>Like it happens in the most of our tutorials, there&#x2019;s <a href="https://github.com/appcoda/StoreKitDemo/blob/master/StoreKitLocalDemoStarter.zip?ref=appcoda.com" class="rank-math-link">a project for you to download</a> and start with. However, and contrarily to other times, here we&#x2019;ll write almost no code at all; just a few bits at the end of the post when we&#x2019;ll talk about unit testing. What we&#x2019;ll focus on is the necessary configuration files that allow to test StoreKit locally, and the available options Xcode provides in order to test various states and conditions of in-app purchases.</p>



<p>The demo project we&#x2019;ll be working on in the upcoming parts of the tutorial is a SwiftUI based application. It&#x2019;s really simple, as it shows a list with three recipes only which are meant to be purchased and therefore to be unlocked. Nothing will happen after they&#x2019;re purchased, but we don&#x2019;t really care about that; what we care about is the behaviour of the app when purchasing under various conditions.</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="422" height="785" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_1_app_sample.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18562" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_1_app_sample.png 422w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_1_app_sample-161x300.png 161w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_1_app_sample-200x372.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_1_app_sample-400x744.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_1_app_sample-50x93.png 50w" sizes="(max-width: 422px) 100vw, 422px"></figure></div>



<p>The three recipes (in-app purchase products) are described in a JSON file called <em>Recipes.json</em> and you can find it in the project navigator along with the rest of the project files. Programmatically, a recipe is represented by an instance of the <code>RecipeInfo</code> class which is implemented in the <em>RecipeInfo.swift</em> file. Recipes are handled by the <code>RecipesModel</code> class, which among others contains the <code>recipes</code> array (a collection of <code>RecipeInfo</code> objects), and it is also responsible for reading the JSON file and decoding the recipe data.</p>



<p><code>RecipesModel</code> class is also the one that triggers the in-app purchase actions, such as loading the in-app purchase products and initiating purchases. It&#x2019;s important to highlight here that all the in-app purchases related code is implemented in the <code>IAPManager</code> class that you can find in the <em>IAPManager.swift</em> file. This class had been presented and implemented step-by-step in <a href="https://www.appcoda.com/in-app-purchases-guide/">this older tutorial</a> where we had talked about in-app purchases thoroughly, and you might want to take a look there too.</p>



<p>A requirement of the <code>IAPManager</code> class is that all <em>product identifiers</em> available for in-app purchases should exist in a <em>property list (.plist)</em> file, called <em>IAP_ProductIDs.plist</em>. You will find it in the project navigator too, and you can open it to see the identifiers matching to the three products we&#x2019;ll be testing today.</p>



<p>Before we get to the end of this part, there&#x2019;s one more <strong>important statement</strong> I&#x2019;d like to make:</p>



<p>In order to test StoreKit properly in Xcode and get the maximum out of it, it&#x2019;s recommended to perform <em>local receipt validation</em>. However, we won&#x2019;t do that here; local receipt validation is a long discussion, probably the topic of one or more new tutorials, so we&#x2019;ll just skip it. We&#x2019;ll do the best we can without validating the fake receipt that Xcode will create for us, but in certain topics, such as subscriptions, we won&#x2019;t go into much depth. We&#x2019;ll see all necessary steps to configure a local test, but we won&#x2019;t actually test anything. In case you have implemented your own local receipt validation mechanism, feel free to move further by following the guides from a link I give you later. To help the UI being in accordance to the purchased state of our recipes in this project, the <em>User Defaults</em> dictionary is used to mark whether recipes have been purchased or not.</p>



<p>Other than that, and after that long description, take your time to explore the demo project, and even visit the previous tutorial and read about the <code>IAPManager</code> class that is used in this project too. Once you&#x2019;re ready, keep reading to unveil the most important aspects of StoreKit testing locally in Xcode.</p>



<h2 class="wp-block-heading">Preparing To Test In-App Purchases Locally</h2>



<p>There are some standard actions that must be taken in order to test in-app purchases locally in Xcode. The first one is to create <em>a configuration file</em> that simulates App Store by containing in-app purchase records. Depending on the kind of the in-app purchases an app offers, <em>multiple configuration files</em> can be created into the same app; for example, there can be one for testing non-consumable in-app purchases and one for testing subscriptions. However, note that only one can be active and used at any given time.</p>



<p>To create a configuration file, open the <strong>File &gt; New &gt; File&#x2026;</strong> menu in Xcode, or just press Cmd+N in your keyboard. In the window that appears with all the available file templates, scroll to bottom under the <strong>Other</strong> section where you&#x2019;ll find the <strong>StoreKit Configuration File</strong>. To spot it easier, you can also type &#x201C;storekit&#x201D; in the search bar.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="735" height="533" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_2_storekit_config_file_template.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18565" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_2_storekit_config_file_template.png 735w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_2_storekit_config_file_template-414x300.png 414w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_2_storekit_config_file_template-200x145.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_2_storekit_config_file_template-680x493.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_2_storekit_config_file_template-400x290.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_2_storekit_config_file_template-50x36.png 50w" sizes="(max-width: 735px) 100vw, 735px"></figure>



<p>Click next in order to give a name to the file that&#x2019;s going to be created and added to the project. We are going to work with non-consumable products here, so give the name <strong>NonConsumables</strong> to it and then click Create. In fact, you can give any name you want, however that cleary indicates what that configuration file is all about.</p>



<p>Once the file appears in the project navigator, click to open it in case it won&#x2019;t open automatically. Currently it&#x2019;s empty, and it&#x2019;s waiting for us to add either in-app purchases or subscriptions. We&#x2019;ll go for the first, and the way to do that is by clicking on the Plus (+) button to the bottom left side of the window.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="804" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-1024x804.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18566" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-1024x804.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-382x300.png 382w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-200x157.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-768x603.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-1240x973.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-860x675.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-680x534.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-400x314.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap-50x39.png 50w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_3_add_iap.png 1477w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>There&#x2019;s a context menu appearing here containing options to add:</p>



<ol><li>A consumable in-app purchase.</li><li>A non-consumable in-app purchase.</li><li>An auto-renewable subscription.</li></ol>



<p>We want to try out non-consumable in-app purchases here, so click on the second menu item. Here&#x2019;s what you&#x2019;ll see:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="277" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-1024x277.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18567" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-1024x277.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-600x162.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-200x54.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-768x207.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-1240x335.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-860x232.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-680x184.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-400x108.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap-50x14.png 50w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_4_empty_iap.png 1448w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>The <strong>Reference</strong> field should contain a short descriptive name for the in-app purchase. In our demo project we&#x2019;re going to have sample recipes for a salad, a spaghetti and a cake, so let&#x2019;s suppose that this record is about the first one; type <em>Salad</em> as the reference name.</p>



<p>The <strong>Product ID</strong> is the product identifier as we would also provide it in the App Store Connect. As I mentioned earlier, you can find all product identifiers that will be used in the app in the <em>IAP_ProductIDs.plist</em> file. The one that we&#x2019;ll use here is the <em>com.appcoda.storekitlocaldemo.salad</em>. This will replace the default value &#x201C;com.temporary.id&#x201D;.</p>



<p>The next field is the <strong>Price</strong> of the in-app purchase. Even though there are price tiers in App Store Connect, here we can provide any value we want as a free text. The price is just for testing reasons, it won&#x2019;t apply to the real in-app purchases and of course, there will be no charging. So feel free to set any price you&#x2019;d like. For this specific in-app purchase that we&#x2019;re configuring here, 0.99 value is just fine. The currency of the price will be the currency matching to the Simulator&#x2019;s locale, or any locale that has been manually selected (we&#x2019;ll talk about that later). So, 0.99 can be dollars, euros, yen, and so on.</p>



<p>Right below the three fields described we just met, there&#x2019;s a checkbox which you can turn on to test the family sharing feature. We won&#x2019;t do that here, so simply leave it unchecked.</p>



<p>Lastly, there&#x2019;s the <strong>Localizations</strong> section. Here is the place where we must provide a display name and a description for our in-app purchase, as we would normally do in the App Store Connect too. Click on the default localization row and a window will be presented as a sheet. Fill the following values in:</p>



<ul><li>Display name: <em>Ceasars Salad</em></li><li>Description: <em>The most popular salad everybody loves!</em></li></ul>



<p>Here&#x2019;s how the in-app purchase should look now configured:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1339" height="403" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18568" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap.png 1339w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap-600x181.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap-1024x308.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap-200x60.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap-768x231.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap-1240x373.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap-860x259.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap-680x205.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap-400x120.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_6_configured_iap-50x15.png 50w" sizes="(max-width: 1339px) 100vw, 1339px"></figure>



<p>The steps described above concern one in-app purchase only. However, in our demo application there are three recipes that we&#x2019;ll offer as in-app purchases, so we have to add and configure the other two in a similar way.</p>



<p>Following the steps as described previously, add two more non-consumable in-app purchase entries and configure them as follows:</p>



<ol><li>For the spaghetti recipe in-app purchase:</li></ol>



<ul><li>Reference name: <em>Spaghetti</em></li><li>Product ID: <em>com.appcoda.storekitlocaldemo.spaghetti</em></li><li>Price: <em>1.19</em></li><li>Localizations &gt; Display Name: <em>Spaghetti &amp; Meatballs</em></li><li>Localizations &gt; Description: <em>A tasty meal that makes you happy!</em></li></ul>



<ol><li>For the cake recipe in-app purchase:</li></ol>



<ul><li>Reference name: <em>Cake</em></li><li>Product ID: <em>com.appcoda.storekitlocaldemo.cake</em></li><li>Price: <em>1.49</em></li><li>Localizations &gt; Display Name: <em>Chocolate Cake</em></li><li>Localizations &gt; Description: <em>The most delicious dessert ever!</em></li></ul>



<p>At the end, you should be able to see the next three in-app purchases in the configuration file:</p>



<div class="wp-block-image"><figure class="alignright size-large"><img loading="lazy" decoding="async" width="281" height="95" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_7_three_iaps_config.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18569" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_7_three_iaps_config.png 281w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_7_three_iaps_config-200x68.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_7_three_iaps_config-50x17.png 50w" sizes="(max-width: 281px) 100vw, 281px"></figure></div>



<p>In case you add in-app purchase records that you don&#x2019;t want to use, select them by clicking on them (keep Ctrl key pressed for more than one record), and then click on the Minus (-) button at the bottom left side of the window.</p>



<p>Finally, when you finish configuring the in-app purchases press Cmd+S to save your changes.</p>



<h2 class="wp-block-heading">Using The StoreKit Configuration File</h2>



<p>With the <em>NonConsumables.storekit</em> file created and configured, the next step is to tell our app that we want to use that instead of the App Store. To do that start by clicking on the StoreKitLocalDemo scheme in Xcode toolbar, and select the <em>Edit Scheme</em> option.</p>



<div class="wp-block-image"><figure class="alignright size-large"><img loading="lazy" decoding="async" width="343" height="97" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_8_edit_scheme.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18570" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_8_edit_scheme.png 343w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_8_edit_scheme-200x57.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_8_edit_scheme-50x14.png 50w" sizes="(max-width: 343px) 100vw, 343px"></figure></div>



<p>Make sure that the <em>Run</em> action is selected on the left column, and then choose the <em>Options</em> tab on the main window. You&#x2019;ll find an option there called <strong>StoreKit Configuration</strong>, with its current value being to <em>None</em>. Click to open the popup button, and you will find the <em>NonConsumables.storekit</em> file we created right there. Select it and close the scheme editor.</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="896" height="508" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_9_scheme_editor.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18571" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_9_scheme_editor.png 896w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_9_scheme_editor-529x300.png 529w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_9_scheme_editor-200x113.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_9_scheme_editor-768x435.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_9_scheme_editor-860x488.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_9_scheme_editor-680x386.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_9_scheme_editor-400x227.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_9_scheme_editor-50x28.png 50w" sizes="(max-width: 896px) 100vw, 896px"></figure></div>



<p>Note that additional <em>.storekit</em> files can be listed along with the <em>NonConsumables.storekit</em> file, but as I have already mentioned and as you just saw, only one can be active at a time.</p>



<h2 class="wp-block-heading">Testing In-App Purchases</h2>



<p>At this point we are able to test for first time in-app purchases locally. Make sure that you have followed all steps as described in the previous two parts, and then run the app in the Simulator. You&#x2019;ll see the three demo recipes listed, where a lock icon exists next to each one to indicate that they have not been purchased yet.</p>



<p>Click on the first (or any other) recipe in the list, and you&#x2019;ll see an alert showing app suggesting to buy it. The interesting thing here is that the alert contains the product display name, description and price as they were defined in the <em>NonConsumables.storekit</em> file. If you make any change on any of those three values in the storekit file, you&#x2019;ll see it being reflected on this alert.</p>



<p>In the presented alert, select to buy the recipe by clicking on the <em>Get recipe for XXX</em> button. The system UI that would appear in a normal purchase from the App Store appears here too in order to simulate the purchase experience, and all you have to do to continue with the transaction is to click on the <em>Confirm</em> button. Of course, no charge will happen, and that&#x2019;s something that is also clarified in the details section of the presented UI.</p>



<p>After confirming the purchase you&#x2019;ll see a system alert notifying that the transaction was successful. The lock icon next to the selected recipe will disappear right after you dismiss that alert, which is the indication in our demo project that the recipe has been purchased.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="260" height="542" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_10_first_purchase.gif" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18572"></figure>



<h2 class="wp-block-heading">The Transactions Manager</h2>



<p>All transactions that take place locally using a storekit file like the one we created previously are visible in a special window in Xcode. This is the transactions manager, and you can present it either by going to the <strong>Debug &gt; StoreKit &gt; Manage Transactions&#x2026;</strong> menu, or by clicking on the <strong>Manage StoreKit Transactions</strong> button in Xcode&#x2019;s status bar while the app is running:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_11_transactions_status_bar.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18573" width="551" height="42" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_11_transactions_status_bar.png 551w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_11_transactions_status_bar-200x15.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_11_transactions_status_bar-400x30.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_11_transactions_status_bar-50x4.png 50w" sizes="(max-width: 551px) 100vw, 551px"></figure>



<p>When transactions manager window is presented, you&#x2019;ll find the transaction that you made in the previous part listed in it.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="912" height="766" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_12_transactions_manager_first.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18574" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_12_transactions_manager_first.png 912w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_12_transactions_manager_first-357x300.png 357w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_12_transactions_manager_first-200x168.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_12_transactions_manager_first-768x645.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_12_transactions_manager_first-860x722.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_12_transactions_manager_first-680x571.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_12_transactions_manager_first-400x336.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_12_transactions_manager_first-50x42.png 50w" sizes="(max-width: 912px) 100vw, 912px"></figure>



<p>What is really great with local testing is that we can delete any transaction that was made so far and test our in-app purchases from start immediately. Using the App Store in order to do the exact same thing we would need to create new test users every time we would like to start testing fresh.</p>



<p>To see that in action, select the transaction you see in the manager window, and either click on the Trash button, or right click on it and select <em>Delete Transaction</em>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="802" height="146" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_13_delete_transaction.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18575" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_13_delete_transaction.png 802w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_13_delete_transaction-600x109.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_13_delete_transaction-200x36.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_13_delete_transaction-768x140.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_13_delete_transaction-680x124.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_13_delete_transaction-400x73.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_13_delete_transaction-50x9.png 50w" sizes="(max-width: 802px) 100vw, 802px"></figure>



<p>Run the app again, but before you click to buy the same recipe again, please make sure to click on the Refresh button so the recipe is marked as non-purchased in the User Defaults dictionary and its visual state to be initialized. After you do so and you see the lock icon again, click to purchase the exact same recipe that you purchased before. You&#x2019;ll see that you&#x2019;ll go through the exact same steps you met previously. With a couple of clicks we managed to revert the app to its original state and to test in-app purchases from scratch, like nothing had already happened before.</p>



<p>Back to the transactions manager again, you&#x2019;ll see that the new transaction is present, this time with a different identifier. Besides just deleting the purchase, you can also refund it through the manager window by selecting the respective option either in the toolbar or by right clicking on it. You can do so if you want now, however there will be no visual update in the UI of our demo app; as declared at the beginning, we won&#x2019;t do any receipt validation here, and refund is something that can be checked only in the receipt. However, if you have your own local receipt validation mechanism, you can pretty easily check if the the transaction is marked as cancelled in the receipt, and update the UI of this demo or any other app accordingly.</p>



<h2 class="wp-block-heading">Testing Interrupted Purchases</h2>



<p>The scenario we tested above is the one everybody wishes for their apps. However, things are not going always as smoothly as we would want, so handling cases out of the ordinary is something that we must take care of as well. Such a case is an interrupted purchase; a purchase that cannot be completed because an action out of the app must be taken by the user. For example, the user might need to update the payment information to the App Store in order to be able to make purchases.</p>



<p>To test interrupted purchases, first select the <em>NonConsumables.storekit</em> file in the project navigator. Then go to menu <strong>Editor &gt; Enable Interrupted Purchases</strong>. By doing so, any purchase you&#x2019;ll be making from now on will be handled as interrupted, so don&#x2019;t forget to go to the <strong>Editor &gt; Disable Interrupted Purchases</strong> menu to switch back to normal later.</p>



<p>The <code>IAPManager</code> class provided in the starter project that contains the in-app purchases related implementation will return an error in case of an interrupted purchase. That error is a <em>SKErrorDomain with value 0</em>, meaning an <em>unknown</em> error. Most of the times you&#x2019;ll want just to inform users that the transaction cannot be completed, and this is what happens in this demo project too. Of course, you can follow a different approach in your own apps and treat that error in a way that you find more proper and suitable.</p>



<p>After having turned interrupted transactions on, run the app and try to purchase a recipe that you haven&#x2019;t purchased already. If you have purchased all of them, then use the transactions manager window to delete them, and don&#x2019;t forget to use the Refresh button in the app to initialize the UI too. Then, start the process of purchasing a recipe, and see what happens right after you confirm it through the system UI; an alert informing that the transaction could not be completed is presented, and you can see the error printed in the console at the same time too.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="422" height="785" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_14_interrupted_transaction.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18576" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_14_interrupted_transaction.png 422w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_14_interrupted_transaction-161x300.png 161w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_14_interrupted_transaction-200x372.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_14_interrupted_transaction-400x744.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_14_interrupted_transaction-50x93.png 50w" sizes="(max-width: 422px) 100vw, 422px"></figure>



<p>In the testing environment that we&#x2019;re working on we can resolve the issue that caused the interrupted transaction and see how our app will behave. Go back to Xcode and open the transactions manager window. You&#x2019;ll find the transaction that was made right there, marked as failed. To proceed, select it and use either the <strong>Resolve Issues</strong> button in the toolbar, or right click on it and choose the <strong>Resolve Issue</strong> option from the context menu.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="801" height="121" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_15_resolve_issue.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18577" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_15_resolve_issue.png 801w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_15_resolve_issue-600x91.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_15_resolve_issue-200x30.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_15_resolve_issue-768x116.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_15_resolve_issue-680x103.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_15_resolve_issue-400x60.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_15_resolve_issue-50x8.png 50w" sizes="(max-width: 801px) 100vw, 801px"></figure>



<p>The fake issue will be resolved and the transaction will continue normally. If you go back to the app, you&#x2019;ll see that the purchase is now complete. At the same time, a new entry will show up in the transactions manager where the selected recipe is marked as purchased.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="801" height="230" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_16_entry_resolved_issue.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18578" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_16_entry_resolved_issue.png 801w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_16_entry_resolved_issue-600x172.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_16_entry_resolved_issue-200x57.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_16_entry_resolved_issue-768x221.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_16_entry_resolved_issue-680x195.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_16_entry_resolved_issue-400x115.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_16_entry_resolved_issue-50x14.png 50w" sizes="(max-width: 801px) 100vw, 801px"></figure>



<h2 class="wp-block-heading">Testing Ask To Buy</h2>



<p>Another option that can be found in the <em>Editor</em> menu when the <em>NonConsumables.storekit</em> file is selected in Xcode is the <strong>Enable Ask to Buy</strong>. By enabling it you can test what will happen if an underaged user initiates the purchase process through your app and the <em>Ask to Buy</em> feature is turned on on their device.</p>



<p>To see it in action make sure to open <em>NonConsumables.storekit</em> by selecting it in the project navigator, and then go to menu <strong>Editor &gt; Enable Ask to Buy</strong>.</p>



<p><em>Note: Make sure that you&#x2019;ve disabled interrupted purchases first.</em></p>



<p>Run the app again and start the purchase process of a recipe. After confirming the purchase you&#x2019;ll get the following system alert:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="422" height="785" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_17_ask_to_buy.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18579" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_17_ask_to_buy.png 422w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_17_ask_to_buy-161x300.png 161w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_17_ask_to_buy-200x372.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_17_ask_to_buy-400x744.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_17_ask_to_buy-50x93.png 50w" sizes="(max-width: 422px) 100vw, 422px"></figure>



<p>By selecting the <em>Ask</em> option you&#x2019;ll see a detailed error logged in the console saying that the payment was complete but with errors. Until the parent or guardian of the underaged user who initiated the purchase will approve or reject it, there&#x2019;s no need to change our UI. However, we must make sure that the recipe will become available in case of approval.</p>



<p>Once again, testing can continue through the transactions manager in Xcode. Open it, and you&#x2019;ll find the transaction we just made being listed there, marked as <em>Pending Approval</em>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="119" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_18_transactions_pending.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18580" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_18_transactions_pending.png 800w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_18_transactions_pending-600x89.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_18_transactions_pending-200x30.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_18_transactions_pending-768x114.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_18_transactions_pending-680x101.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_18_transactions_pending-400x60.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_18_transactions_pending-50x7.png 50w" sizes="(max-width: 800px) 100vw, 800px"></figure>



<p>Select the transaction and use the toolbar or right click on it and select the <strong>Approve Transaction</strong> to approve it. Switch back to the running application in the Simulator, and you&#x2019;ll see that the recipe has being unlocked.</p>



<p>Read more about the Ask to Buy feature <a href="https://support.apple.com/en-us/HT201089?ref=appcoda.com">here</a>.</p>



<h2 class="wp-block-heading">Changing The Storefront</h2>



<p>While testing in-app purchases locally in Xcode 12, it&#x2019;s possible to change the default storefront and make sure that your app presents the price of the selected product properly formatted using the correct currency. Responsible for formatting properly the price in our demo app is the <code>getPriceFormatted(for:)</code> method of the <code>IAPManager</code> class. It&#x2019;s already used as needed in the <code>RecipesView</code>, so all we have to do is to test if it&#x2019;s working as expected. Before we continue, remember that during the configuration of the in-app purchases in the storekit file we set just a numerical value as the price; we did not set any currency. The displayed currency depends on the selected storefront.</p>



<p>Back in Xcode, open the <em>NonConsumables.storekit</em> file, and then go to <strong>Editor &gt; Default Storefront &gt; Greece</strong> menu. This will simulate the use of the Greek App store, and the euro sign will be displayed instead of the dollar sign next to the price when we&#x2019;ll purchase a recipe.</p>



<p>After you make the above change, run the app and initiate a new purchase. You&#x2019;ll see that this time the Euro currency sign is displayed next to the price value.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="422" height="785" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_19_change_storefront.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18581" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_19_change_storefront.png 422w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_19_change_storefront-161x300.png 161w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_19_change_storefront-200x372.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_19_change_storefront-400x744.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_19_change_storefront-50x93.png 50w" sizes="(max-width: 422px) 100vw, 422px"></figure>



<h2 class="wp-block-heading">Changing The Default Localization</h2>



<p>In conjunction to the default storefront, you can also change the default localization that will affect the displayed product metadata. To do so, make sure that the <em>NonConsumables.storekit</em> file is open, and then go to <strong>Editor &gt; Default Localization &gt; Greek</strong> menu (or choose any other localization you want).</p>



<p>However, simply changing the default localization is not enough. We must provide the respective display name and description that will be used for that localization in the configuration file. Let&#x2019;s do that for the Salad in-app purchase.</p>



<p><em>Note: If you run the app without providing localized display name and description for a product, then no title and description will appear in the alert that prompts to buy the recipe.</em></p>



<p>In the <em>NonConsumables.storekit</em> file select the Salad in app purchase. Then, click on the Plus (+) button in the <em>Localizations</em> section. In the localization configuration window, first select the Greek locale (or any other locale you prefer). Then provide a localized display name and description in the language you prefer, or use the example given here. For the Greek locale, that would be:</p>



<ul><li>Display name: <em>&#x3A3;&#x3B1;&#x3BB;&#x3AC;&#x3C4;&#x3B1; &#x3C4;&#x3BF;&#x3C5; &#x39A;&#x3B1;&#x3AF;&#x3C3;&#x3B1;&#x3C1;&#x3B1;</em></li><li>Description: <em>&#x397; &#x3B4;&#x3B9;&#x3AC;&#x3C3;&#x3B7;&#x3BC;&#x3B7; &#x3C3;&#x3B1;&#x3BB;&#x3AC;&#x3C4;&#x3B1; &#x3C0;&#x3BF;&#x3C5; &#x3CC;&#x3BB;&#x3BF;&#x3B9; &#x3BB;&#x3B1;&#x3C4;&#x3C1;&#x3B5;&#x3CD;&#x3BF;&#x3C5;&#x3BD;!</em></li></ul>



<p>Click on the Done button, and the new localization will appear in the Localizations list.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="397" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization-1024x397.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18582" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization-1024x397.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization-600x233.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization-200x78.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization-768x298.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization-860x333.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization-680x264.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization-400x155.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization-50x19.png 50w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_20_greek_localization.png 1027w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Run the app now, and initiate a purchase process. You&#x2019;ll see that the message appearing in the alert is now translated to the selected localization, and the currency of the price is in accordance with that localization.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="422" height="785" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_21_localized_alert.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18583" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_21_localized_alert.png 422w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_21_localized_alert-161x300.png 161w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_21_localized_alert-200x372.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_21_localized_alert-400x744.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_21_localized_alert-50x93.png 50w" sizes="(max-width: 422px) 100vw, 422px"></figure>



<p>Of course, in a real app the UI should be translated too, however what we focus on now is the in-app purchases only; so just don&#x2019;t mind about the rest of the UI that is still in English.</p>



<h2 class="wp-block-heading">Creating A Configuration File To Test Subscriptions</h2>



<p>Even though we won&#x2019;t test subscriptions as they require receipt validation in order to properly work, we&#x2019;ll go briefly through the steps of creating a storekit configuration file which includes subscription records.</p>



<p><em>Note: Don&#x2019;t forget to edit the app scheme and select any new storekit configuration file in the StoreKit Configuration popup (Run action, Options tab) that you&#x2019;d like to use for testing.</em></p>



<p>To start, go to <strong>File &gt; New &gt; File&#x2026;</strong> menu, and then search for the &#x201C;storekit&#x201D; file template. Select it and proceed by naming it as <em>Subscriptions</em>. Once you see the <em>Subscriptions.storekit</em> file in the project navigator, click to open it.</p>



<p>The first move here is to add a new auto-renewable subscription record to the configuration file. Go to the Plus (+) button to the bottom left side of the configuration window, click on it and select the <strong>Add Auto-Renewable Subscription</strong> option from the context menu.</p>



<p>Since this is the first subscription added, you&#x2019;ll see a window asking to create a <em>subscription group</em>. Such a group can contain multiple subscriptions, but users can subscribe to one of them only at a time, having however the ability to switch subscriptions that belong to the same group whenever they want.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="695" height="241" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_22_ask_sub_group.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18584" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_22_ask_sub_group.png 695w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_22_ask_sub_group-600x208.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_22_ask_sub_group-200x69.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_22_ask_sub_group-680x236.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_22_ask_sub_group-400x139.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_22_ask_sub_group-50x17.png 50w" sizes="(max-width: 695px) 100vw, 695px"></figure>



<p>Even if you are going to have one subscription only a group is necessary to be created here, so just type a name in, such as <em>MySubscriptions</em> or anything else you want. Click on the Done button to proceed.</p>



<p>As you can see in the subscription configuration, there are several fields that we can provide values for, depending always on what we&#x2019;d like to test.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="538" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-1024x538.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18586" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-1024x538.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-571x300.png 571w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-200x105.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-768x403.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-1240x651.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-860x452.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-680x357.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-400x210.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields-50x26.png 50w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_23_sub_fields.png 1422w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>The first section under the <em>Auto-Renewable Subscription</em> section is pretty similar to the set of fields we filled in for each in-app purchase in the <em>NonConsumables.storekit</em> file. Each subscription should have a reference name, a product identifier, and a price that users should pay when the subscription is renewed. Additionally, here we have the <strong>Subscription Duration</strong> field for specifying how long the subscription we&#x2019;re about to test will last.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="908" height="220" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_24_sub_initial_fields.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18587" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_24_sub_initial_fields.png 908w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_24_sub_initial_fields-600x145.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_24_sub_initial_fields-200x48.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_24_sub_initial_fields-768x186.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_24_sub_initial_fields-860x208.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_24_sub_initial_fields-680x165.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_24_sub_initial_fields-400x97.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_24_sub_initial_fields-50x12.png 50w" sizes="(max-width: 908px) 100vw, 908px"></figure>



<p>Right below there&#x2019;s the <strong>Introductory Offer</strong> section. Use it if you&#x2019;re planning to provide a one-time introductory offer to the users and you want to test whether your app works as expected or not. To configure the introductory offer start by clicking on the <strong>Offer Type</strong> popup button. Select one of the three options (besides None) depending on the subscription kind:</p>



<ul><li><em>Pay as you go</em></li><li><em>Pay up front</em></li><li><em>Free</em></li></ul>



<p>For any selected option you have to specify the offer duration in a new field that appears, and for the first two options there&#x2019;s a price field to fill in as well that contains the offer&#x2019;s lower price.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="931" height="144" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_25_intro_offer.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18588" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_25_intro_offer.png 931w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_25_intro_offer-600x93.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_25_intro_offer-200x31.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_25_intro_offer-768x119.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_25_intro_offer-860x133.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_25_intro_offer-680x105.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_25_intro_offer-400x62.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_25_intro_offer-50x8.png 50w" sizes="(max-width: 931px) 100vw, 931px"></figure>



<p>Upon testing the introductory offer, the offer price (or free) specified right above should be displayed in the system sheet presented to confirm the payment. Remember that any transaction is listed in the transactions manager window, so make sure to delete them from there if you want to start fresh.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="422" height="785" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_26_intro_offer_sample.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18589" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_26_intro_offer_sample.png 422w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_26_intro_offer_sample-161x300.png 161w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_26_intro_offer_sample-200x372.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_26_intro_offer_sample-400x744.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_26_intro_offer_sample-50x93.png 50w" sizes="(max-width: 422px) 100vw, 422px"></figure>



<p>To test if your subscription will be renewed properly after the period of the introductory offer, you can speed things up by going back to Xcode and the <em>Subscriptions.storekit</em> file. Then go to <strong>Editor &gt; Time Rate</strong> menu, and choose a time rate that you find fast enough. Usually, &#x201C;1 second is 1 day&#x201D; is the option to go if you want to test quickly. Once the time period has expired, switch back to a slower time rate, and test if your app renews the subscription properly by reading the proper fields in the receipt.</p>



<p>Besides the introductory offer that you can test, there&#x2019;s also the <strong>Promotional Offers</strong> section. Here you can define offers that you&#x2019;d like to test for each subscription, which you can display either when the subscription expires or when you decide it&#x2019;s the best time depending on certain conditions.</p>



<p>To create a promotional offer click on the Plus button in that section and fill the required values in. Type in custom value for the reference name and the product code, and then select the offer type, its duration, and a price if it&#x2019;s not a free offer. Once again, use the <em>Editor &gt; Time Rate</em> menu to speed up or slow down the time rate while testing.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="155" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer-1024x155.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18590" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer-1024x155.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer-600x91.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer-200x30.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer-768x116.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer-860x130.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer-680x103.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer-400x60.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer-50x8.png 50w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_28_promo_offer.png 1027w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Lastly, don&#x2019;t forget to set a display name and a description for the default localization that will be displayed to users upon purchasing the subscription. This is similar to the localization values we also met previously in the in-app purchases storekit configuration file.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="157" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization-1024x157.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18591" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization-1024x157.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization-600x92.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization-200x31.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization-768x118.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization-860x132.png 860w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization-680x104.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization-400x61.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization-50x8.png 50w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_29_sub_localization.png 1049w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Note that for any new subscription record you&#x2019;ll add to this configuration file, you&#x2019;ll be given the option either to append it to the current subscriptions group, or create a new group to contain it.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="695" height="242" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_30_new_sub.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18592" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_30_new_sub.png 695w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_30_new_sub-600x209.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_30_new_sub-200x70.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_30_new_sub-680x237.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_30_new_sub-400x139.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_30_new_sub-50x17.png 50w" sizes="(max-width: 695px) 100vw, 695px"></figure>



<p><em>You are recommended to take a look at the guides you&#x2019;ll find <a href="https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_in_xcode?ref=appcoda.com">here</a> about testing subscriptions.</em></p>



<h2 class="wp-block-heading">Writing Unit Tests</h2>



<p>Besides all the manual work that can be done to test in-app purchases locally as shown in the previous parts, it&#x2019;s also possible to create unit and UI tests thanks to a new framework called <code>StoreKitTest</code>. This framework provides the <code>SKTestSession</code> class, which in turn offers several methods and properties in order to configure test conditions and perform fake transactions.</p>



<p>We&#x2019;re going to write a couple of unit tests here and get a small, first taste of the <code>StoreKitTest</code> framework. Begin by opening the <em>StoreKitLocalDemoTests.swift</em> file; the place to write unit tests in our project. Then, go to the top of the file, and right after the <code>import XCTest</code> line, import the <code>StoreKitTest</code> framework:</p>



<pre class="wp-block-code"><code>import StoreKitTest</code></pre>



<p>In our first test we&#x2019;re going to do something really simple; we&#x2019;ll make a purchase and we&#x2019;ll ensure that it&#x2019;s completed successfully. Since it&#x2019;s a test environment things can&#x2019;t go wrong, but it&#x2019;s a good chance to meet a few bits of the new API and validate that our in-app purchases code works properly.</p>



<p>Let&#x2019;s define the following new method:</p>



<pre class="wp-block-code"><code>func testSaladPurchase() throws {

}</code></pre>



<p>Initially, we&#x2019;ll create a <code>SKTestSession</code> instance through which we&#x2019;ll test the in-app purchase:</p>



<pre class="wp-block-code"><code>func testSaladPurchase() throws {
    let session = try SKTestSession(configurationFileNamed: &quot;NonConsumables&quot;)
}</code></pre>



<p>See that upon initialization we provide the name of the storekit configuration file we want to use.</p>



<p>Then, in order to have everything run automatically from start to finish, let&#x2019;s disable the appearance of any system dialogs and UI with the next line:</p>



<pre class="wp-block-code"><code>func testSaladPurchase() throws {
    ...
    session.disableDialogs = true
}</code></pre>



<p>Lastly, we&#x2019;ll make the purchase using the <code>buyProduct(productIdentifier:)</code> method of the <code>SKTestSession</code> class through the <code>session</code> object. This is a method that can throw an exception, and since this is the last line of our method, we&#x2019;ll call it as the argument of a <code>XCTAssertNoThrow(_:)</code> method:</p>



<pre class="wp-block-code"><code>func testSaladPurchase() throws {
    ...
    XCTAssertNoThrow(try session.buyProduct(productIdentifier: &quot;com.appcoda.storekitlocaldemo.salad&quot;))
}</code></pre>



<p>Notice that it&#x2019;s necessary to specify the product identifier matching to the in-app purchase we want to test. Here&#x2019;s the full method:</p>



<pre class="wp-block-code"><code>func testSaladPurchase() throws {
    let session = try SKTestSession(configurationFileNamed: &quot;NonConsumables&quot;)
    session.disableDialogs = true
    XCTAssertNoThrow(try session.buyProduct(productIdentifier: &quot;com.appcoda.storekitlocaldemo.salad&quot;))
}</code></pre>



<p>Let&#x2019;s run the test now. Click on the small play icon on the left side of the method&#x2019;s name, and wait until the test is finished. It should be successful, if it isn&#x2019;t, please make sure that you followed all steps here as described.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="855" height="99" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_31_test_play_button.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18593" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_31_test_play_button.png 855w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_31_test_play_button-600x69.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_31_test_play_button-200x23.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_31_test_play_button-768x89.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_31_test_play_button-680x79.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_31_test_play_button-400x46.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_31_test_play_button-50x6.png 50w" sizes="(max-width: 855px) 100vw, 855px"></figure>



<p>To see the purchase that was just made, first run the app by pressing Cmd+R; then open the transactions manager; the transaction will be listed there.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="800" height="149" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_32_test_transaction.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18594" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_32_test_transaction.png 800w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_32_test_transaction-600x112.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_32_test_transaction-200x37.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_32_test_transaction-768x143.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_32_test_transaction-680x127.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_32_test_transaction-400x75.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_32_test_transaction-50x9.png 50w" sizes="(max-width: 800px) 100vw, 800px"></figure>



<p>It&#x2019;s possible to delete all previous transactions each time a test is running. Right after the <code>session</code> initialization add the next line:</p>



<pre class="wp-block-code"><code>session.clearTransactions()</code></pre>



<p>Let&#x2019;s pass to the second test now. This time we&#x2019;ll test the Ask to Buy scenario in a new test method:</p>



<pre class="wp-block-code"><code>func testAskToBuy() throws {

}</code></pre>



<p>As previously, we&#x2019;ll start by initializing a test session object and by performing some basic configuration:</p>



<pre class="wp-block-code"><code>let session = try SKTestSession(configurationFileNamed: &quot;NonConsumables&quot;)
session.clearTransactions()
session.disableDialogs = true</code></pre>



<p>To enable the Ask to Buy feature we just need to set true to the following flag:</p>



<pre class="wp-block-code"><code>session.askToBuyEnabled = true</code></pre>



<p>Now we can buy the same in-app purchase as before:</p>



<pre class="wp-block-code"><code>XCTAssertNoThrow(try session.buyProduct(productIdentifier: &quot;com.appcoda.storekitlocaldemo.salad&quot;))</code></pre>



<p>If the above assertion is successful, then a new transaction will be created with the purchase pending for approval. In this case, the transaction that was made remains in the <code>deferred</code> state and it&#x2019;s completed only once it gets approved or rejected. To test that, let&#x2019;s add the next two assertions:</p>



<pre class="wp-block-code"><code>XCTAssertTrue(session.allTransactions().count == 1)
XCTAssertTrue(session.allTransactions()[0].state == .deferred)</code></pre>



<p>Here&#x2019;s the entire method so far:</p>



<pre class="wp-block-code"><code>func testAskToBuy() throws {
    let session = try SKTestSession(configurationFileNamed: &quot;NonConsumables&quot;)
    session.clearTransactions()
    session.disableDialogs = true
    session.askToBuyEnabled = true

    XCTAssertNoThrow(try session.buyProduct(productIdentifier: &quot;com.appcoda.storekitlocaldemo.salad&quot;))

    XCTAssertTrue(session.allTransactions().count == 1)
    XCTAssertTrue(session.allTransactions()[0].state == .deferred)
}</code></pre>



<p>Run the test, and once it&#x2019;s marked as successful, run the app and open the transactions manager. You will find the in-app purchase in the pending approval state:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="801" height="163" src="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_33_pending_approval_test.png" alt="Testing In-App Purchases Using StoreKit in Xcode" class="wp-image-18595" srcset="https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_33_pending_approval_test.png 801w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_33_pending_approval_test-600x122.png 600w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_33_pending_approval_test-200x41.png 200w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_33_pending_approval_test-768x156.png 768w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_33_pending_approval_test-680x138.png 680w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_33_pending_approval_test-400x81.png 400w, https://www.appcoda.com/content/images/wordpress/2020/08/storekit_testing_33_pending_approval_test-50x10.png 50w" sizes="(max-width: 801px) 100vw, 801px"></figure>



<p>Let&#x2019;s add one last assertion in the above test method where we&#x2019;ll be approving the purchase:</p>



<pre class="wp-block-code"><code>func testAskToBuy() throws {
    ...

    XCTAssertNoThrow(try session.approveAskToBuyTransaction(identifier: session.allTransactions()[0].identifier))
}</code></pre>



<p>The identifier that the <code>approveAskToBuyTransaction(identifier:)</code> method requires is the transaction identifier as shown in the transactions manager.</p>



<p>Run the test again, and then run the app and open the transactions manager; this time the transaction is marked as purchased because it was approved with the last line we just added.</p>



<p>In the above two tests we met a few methods and properties of the <code>SKTestSession</code> class. I prompt you to <a href="https://developer.apple.com/documentation/storekittest/sktestsession?ref=appcoda.com">read more</a> about this class and all the available API to use, so you can create tests that can cover all possible cases when dealing with in-app purchases.</p>



<h2 class="wp-block-heading">Summary</h2>



<p>Testing StoreKit locally is a game-changer when the implementation of an app comes to in-app purchases. It can really save a significant amount of time and allows to focus on the important things; how to make an app work properly when it offers in-app purchases. Of course, this doesn&#x2019;t mean that testing with real in-app purchase records in the App Store Connect shouldn&#x2019;t be done at all. </p>



<p>On the contrary, that&#x2019;s the next step once we ensure that our app works properly after testing locally. In any case, I hope that you found some valuable and interesting stuff among the lines of this tutorial, and please make sure to watch the <a href="https://developer.apple.com/videos/play/wwdc2020/10659/?ref=appcoda.com">Introducing StoreKit Testing in Xcode</a> session of WWDC20. Enjoy testing StoreKit!</p>



<p>For reference, you can download the complete project <a href="https://github.com/appcoda/StoreKitDemo/?ref=appcoda.com" class="rank-math-link">here</a>.</p>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[Using MusicKit and Apple Music API to Build a Music Player]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>Hey everyone and welcome back to the second and final part of this tutorial series where we explore the intricacies of Apple&#x2019;s <strong>MusicKit</strong> by building our very own music player in <strong>SwiftUI</strong> that can stream songs from our Apple Music account. If you haven&#x2019;t read Part</p>]]></description><link>https://www.appcoda.com/musickit-music-api/</link><guid isPermaLink="false">66612a0f166d3c03cf0114d6</guid><category><![CDATA[iOS Programming]]></category><category><![CDATA[SwiftUI]]></category><dc:creator><![CDATA[Sai Kambampati]]></dc:creator><pubDate>Fri, 24 Jul 2020 12:48:55 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2020/07/hu-ul54pfqi.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2020/07/hu-ul54pfqi.jpg" alt="Using MusicKit and Apple Music API to Build a Music Player"><p>Hey everyone and welcome back to the second and final part of this tutorial series where we explore the intricacies of Apple&#x2019;s <strong>MusicKit</strong> by building our very own music player in <strong>SwiftUI</strong> that can stream songs from our Apple Music account. If you haven&#x2019;t read Part 1, you can do that <a href="https://www.appcoda.com/musickit-music-player-swiftui/">here</a>.</p>



<p>In the last tutorial, we looked at how to create a MusicKit Identifier for our Apple Developer account, created a JSON Web Token private key, and we were able to successfully make web requests to the Apple Music API. At the end of the tutorial, we also built the UI of our music player and were able to make it look like below.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18313" width="1473" height="1434" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1.png 2946w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-308x300.png 308w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-1024x997.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-200x195.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-768x747.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-1536x1495.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-2048x1993.png 2048w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-1680x1635.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-1240x1207.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-860x837.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-680x662.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-400x389.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-1-50x49.png 50w" sizes="(max-width: 1473px) 100vw, 1473px"></figure>



<p>In this tutorial, we&#x2019;ll start making calls to the Apple Music API to populate our app with real data. We&#x2019;ll also look at how to control media playback with the <code>MediaPlayer</code> framework and enhance the app to this.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="489" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-1024x489.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18459" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-1024x489.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-600x287.png 600w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-200x96.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-768x367.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-1536x734.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-1680x802.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-1240x592.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-860x411.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-680x325.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-400x191.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-50x24.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Cool, right? Let&#x2019;s get started.</p>



<p><em><strong>Note</strong>: This tutorial was made using Xcode 11.4 and Swift 5.1. An active Apple Music subscription will be needed in order to test the app out. You will also need to run your app on a real device because as of this time, the Simulator does not support Apple Music playback.</em></p>



<h2 class="wp-block-heading">Apple Music API vs iTunes Search API</h2>



<p>If you&#x2019;ve worked with podcasts, tv shows, or any other Apple generated media content, you must have come across the iTunes Search API. The <a href="https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/iTuneSearchAPI/index.html?ref=appcoda.com" class="rank-math-link">iTunes Search API</a> lets you search for content in the iTunes Store, App Store, and iBooks Store. This will give you access to information about apps, books, movies, podcasts, music, music videos, audiobooks, and TV shows. The best part about using this API is that it&#x2019;s completely free so you can get updated information, on the fly, for no additional cost.</p>



<p>But why do we use the <a href="https://developer.apple.com/documentation/applemusicapi?ref=appcoda.com" class="rank-math-link">Apple Music API</a> instead of the iTunes Search API? This is because of how much information and power the Apple Music API can deliver. While the Apple Music API provides the same functionality as the iTunes Search API (fetching information about music and music videos), the Apple Music API takes it to the next level by accessing a user&#x2019;s personal library and recommendations. </p>



<p>This means your app can leverage a user&#x2019;s playlists, songs, or ratings for their content. This is why it&#x2019;s required for your user to have an Apple Music account if you will be using the API. Another important reason why the Apple Music API is better over the iTunes Search API is because it is built to work harmoniously with the <code>MediaPlayer</code> framework. As you&#x2019;ll see, streaming audio is a breeze with the Apple Music API. Let&#x2019;s get started!</p>



<h2 class="wp-block-heading">Creating our Classes</h2>



<p>Due to the nature of SwiftUI, making URL calls within our <code>structs</code> can get really complicated. Furthermore, it can get pretty complicated to populate our UI with different information gathered from different songs. This is why we&#x2019;ll create an <code>AppleMusicAPI</code> class that will contain the functions we&#x2019;ll frequently use in our app and a <code>Song</code> structure to make it easier to populate our UI.</p>



<p>Before we begin, download <a href="https://github.com/SwiftyJSON/SwiftyJSON/blob/master/Source/SwiftyJSON/SwiftyJSON.swift?ref=appcoda.com" class="rank-math-link">SwiftyJSON.swift</a> and add the file to your project. This file contains the code for the popular library <code>SwiftyJSON</code>. This is a tremendous tool when making HTTP requests and receiving and parsing JSON responses. You can find more information about <code>SwiftyJSON</code> <a href="https://github.com/SwiftyJSON/SwiftyJSON?ref=appcoda.com" class="rank-math-link">here</a>.</p>



<p>To begin, choose to File &gt; New &gt; File. From the popup that appears, select <strong>Swift file</strong>. Name this file <em>AppleMusicAPI.swift</em> and save this file in the default location. You should now have a template file as shown below.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18316" width="1792" height="1078" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2.png 3584w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-2048x1232.png 2048w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-music-player-2-50x30.png 50w" sizes="(max-width: 1792px) 100vw, 1792px"></figure>



<p>Similarly, let&#x2019;s create a <code>struct</code> for our songs. Go to File &gt; New &gt; File and select <strong>Swift file</strong>. Name this file as <em>Song.swift</em> and save this file. We&#x2019;ll begin creating our <code>Song</code> structure first.</p>



<p>Add the following code below <code>import Foundation</code>:</p>



<pre class="wp-block-code"><code>struct Song {
    var id: String
    var name: String
    var artistName: String
    var artworkURL: String

    init(id: String, name: String, artistName: String, artworkURL: String) {
        self.id = id
        self.name = name
        self.artworkURL = artworkURL
        self.artistName = artistName
    }
}</code></pre>



<p>The code above creates a simple structure for <code>Song</code>. In case if you&#x2019;re not familiar with structures, don&#x2019;t worry. A structure is a type of class that helps make your code more concise, especially when dealing with structural data. Structures, just like classes, can define properties, methods, and initializers to set up their initial state. This is what we are doing with our <code>init</code> method. We are providing a default initializer method for the <code>Song</code> structure that lets a user input the ID, name, artist&#x2019;s name, and album artwork&#x2019;s URL.</p>



<p>Now switch over to the <strong>AppleMusicAPI.swift</strong> file. Here, we&#x2019;ll be implementing a class called <code>AppleMusicAPI</code> that stores our developer token and a bunch of methods that will help when playing our song through our app.</p>



<p>Remove <code>import Foundation</code> and Add the following code to <strong>AppleMusicAPI.swift</strong>:</p>



<pre class="wp-block-code"><code>// 1
import StoreKit

// 2
class AppleMusicAPI {
    // 3
    let developerToken = &quot;YOUR DEVELOPER TOKEN FROM PART 1&quot;

    // 4
    func getUserToken() -&gt; String {
        var userToken = String()

        return userToken
    }
}</code></pre>



<p>The above code is pretty self-explanatory but don&#x2019;t worry if this is a little unclear. Here&#x2019;s what the above function does.</p>



<ol><li>First, we import the <code>StoreKit</code> framework. This helps us access a lot of built-in methods that can communicate with the Apple Music API.</li><li>Here, you&#x2019;ll notice we&#x2019;re defining a <strong>class</strong> called <code>AppleMusicAPI</code>. This makes it easier to manage multiple instances of this class and reference the methods from other views in our app.</li><li>Here we&#x2019;re defining a constant <code>developerToken</code> containing the developer token we created in Part 1 on this tutorial series. This makes it easier to call the token when communicating with the API.</li><li>Finally, we define our first method in this class: <code>getUserToken()</code>. As mentioned earlier, the Apple Music API can get a user&#x2019;s library and playlists. This is only possible if we receive a token that is identifiable to a particular user.</li></ol>



<p>Let&#x2019;s finish implementing the rest of the <code>getUserToken</code> method.</p>



<pre class="wp-block-code"><code>func getUserToken() -&gt; String {
    var userToken = String()

    // 1
    let lock = DispatchSemaphore(value: 0)

    // 2
    SKCloudServiceController().requestUserToken(forDeveloperToken: developerToken) { (receivedToken, error) in
        // 3
        guard error == nil else { return }
        if let token = receivedToken {
            userToken = token
            lock.signal()
        }
    }

    // 4
    lock.wait()
    return userToken
}</code></pre>



<p>You might face some new code in the above snippet. Don&#x2019;t worry though as most of it will be explained.</p>



<ol><li>First, we define a <code>lock</code> that is of type <code>DispatchSemaphore</code>. What is a <code>DispatchSemaphore</code>? A dispatch semaphore is an efficient implementation of halting a thread until a particular message has been passed. This &#x201C;locks&#x201D; a thread from executing more code until a signal has been given.</li><li>We access the <code>SKCloudServiceController().requestUserToken()</code> method to get a token that authenticates the user in personalized Apple Music API requests. Notice how we use our constant <code>developerToken</code> in this method. It&#x2019;s definitely easier than typing the long string again and again.</li><li>Here, we write some code to error check what the <code>requestUserToken()</code> function returns. If <code>receivedToken</code> is not empty, we set it equal to our <code>userToken</code> variable from above. Notice, afterwards, we call <code>lock.signal()</code>. This lets the dispatch semaphore we create earlier know that it&#x2019;s ok to start executing remaining code.</li><li>Since this method executes asynchronously, it&#x2019;s possible that when <code>getUserToken()</code> executes, it can skip to the line <code>return userToken</code>, even before a token is received from the <code>SKCloudServiceController</code>. By adding the <code>lock.wait()</code> line of code, this tells the code to halt executing any further code until a signal is given (as we implemented in Step 3).</li></ol>



<p><strong>Note</strong>: Dispatch sophomores must be used with caution. This can transform code to execute synchronously which can slow down an app or not update UI in time. In fact, if <code>lock.signal</code> is not called, the app will forever remain stuck until the user restarts the app. Thus, it&#x2019;s not advised to use this in big production apps. However, for our purposes, it&#x2019;s completely acceptable.</p>



<p>Now, let&#x2019;s implement our next method: <code>fetchStorefront()</code>. </p>



<p>A storefront is an object that represents the iTunes Store territory that the content is available in. When we perform a search using the Apple Music API, we&#x2019;d like to show results relevant to our user&#x2019;s location. Beneath, <code>getUserToken()</code>, add the following method:</p>



<pre class="wp-block-code"><code>func fetchStorefrontID() -&gt; String {
    // 1
    let lock = DispatchSemaphore(value: 0)
    var storefrontID: String!

    // 2
    let musicURL = URL(string: &quot;https://api.music.apple.com/v1/me/storefront&quot;)!
    var musicRequest = URLRequest(url: musicURL)
    musicRequest.httpMethod = &quot;GET&quot;
    musicRequest.addValue(&quot;Bearer \(developerToken)&quot;, forHTTPHeaderField: &quot;Authorization&quot;)
    musicRequest.addValue(getUserToken(), forHTTPHeaderField: &quot;Music-User-Token&quot;)

    // 3
    URLSession.shared.dataTask(with: musicRequest) { (data, response, error) in
        guard error == nil else { return }

        // 4
        if let json = try? JSON(data: data!) {
            print(json.rawString())
        }
    }.resume()

    // 5
    lock.wait()
    return storefrontID
}</code></pre>



<ol><li>Just like earlier, we create a dispatch semaphore called <code>lock</code> to make sure that the function returns a <code>storefrontID</code> only after the data has been received from our URL request.</li><li>We create a <code>URLRequest</code> using the Apple Music API url. A lot of the details about handling requests and responses from the Apple Music API can be found <a href="https://developer.apple.com/documentation/applemusicapi/handling_requests_and_responses?ref=appcoda.com" class="rank-math-link">here</a>, but here&#x2019;s the gist. To compose a request to the API, first specify the root path, <em>https://api.music.apple.com/v1/ &#xA0;</em>. Here, we specify the <em>storefront</em> component. Using a GET Request, we create a request, adding our developer token in the header.</li><li>Next, we use <code>URLSession</code> to send <code>musicRequest</code>. This is very similar to performing any networking requests for either obtaining images or data. As the <code>.dataTask</code> method is built, we are returned with three constants: <code>data</code> (the data the network response sends back), <code>response</code> (details about the response), and <code>error</code>(this may be nil if there is no error). After checking to make sure there is no error, we move to Step 4.</li><li>The data we get is a JSON payload. A payload is the part of transmitted data that is the actual intended message. Using the <code>SwiftyJSON</code> library we added earlier, we&#x2019;ll print the raw JSON output before parsing it. Notice that we&#x2019;re not calling <code>lock.signal()</code> here because we&#x2019;re not setting anything to the <code>storefrontID</code>. If we did call <code>lock.signal()</code>, our app would crash when testing it. We&#x2019;ll add the signal when we parse our JSON result.</li><li>Finally, we ask the dispatch semaphore to wait before returning the storefront&#x2019;s ID.</li></ol>



<p>This was a lot of code so now is a good time to make sure everything is working properly. We&#x2019;ll switch to <strong>ContentView.swift</strong> and add an <code>onAppear</code> function to our <code>TabView</code>. Whatever code we place inside this method will be executed when <code>TabView</code> is displayed to the user. The code we&#x2019;ll place inside will ask the user for permission to access their media library and upon authorization, will call the <code>fetchStorefront()</code> method which will print the JSON payload.</p>



<p>Let&#x2019;s do it! At the top of the file, add <code>import StoreKit</code> and then make your <code>TabView</code> view look as such</p>



<pre class="wp-block-code"><code>TabView(selection: $selection) {
// Previous Code
    ...
}
.accentColor(.pink)
.onAppear() {
    SKCloudServiceController.requestAuthorization { (status) in
        if status == .authorized {
            print(AppleMusicAPI().fetchStorefrontID())
        }
    }
}</code></pre>



<p>These few lines of code are easily comprehendible. We ask the <code>SKCloudServiceController</code> (remember, this is an object provided by <code>StoreKit</code> that determines the current capabilities of the user&#x2019;s music library) for authorization to access a user&#x2019;s media library. If the user authorizes this access, we run <code>print(AppleMusicAPI().fetchStorefrontID())</code> which will print the JSON payload of the request.</p>



<p>Notice how we call out <code>AppleMusicAPI</code> class. Similar to <code>ContentView</code> in SwiftUI or <code>ViewController</code> in storyboard-based Swift, by adding the pair of parentheses after the class&#x2019;s name, we are initializing it which gives us access to all its constants and methods, such as the <code>fetchStorefrontID()</code> method.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18436" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-6.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Now before we run the app to make sure everything is functioning as expected, we need to make a slight addition to our <strong>Info.plist</strong>. We need to add the following property that gives gives a description to the user what we need access to their music library for. The key is <code>Privacy - Media Library Usage Description</code> and the value can be any message you wish it to be that adequately informs users what the data will be used for.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18437" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-7.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Now we can run out app!</p>



<p><em>You&#x2019;ll need to run the app on a physical device with an active Apple Music subscription. Unfortunately, the simulator does not have the Music app so accessing a user&#x2019;s Apple Music account is near impossible. Having an active Apple Music subscription lets you test the features of your app on your account.</em></p>



<p>After authorizing the app to access your Apple Music account, you should wait for some time and expect an output that looks like the one below.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18438" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-8.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Don&#x2019;t worry about the error messages stating something along the liens of &#x201C;Unable to get the local account&#x201D;. Beneath that, you&#x2019;ll see a JSON string printed out. This goes to show that our code is working. Let&#x2019;s go back to <strong>AppleMusicAPI.swift</strong> and finish the rest of the <code>fetchStorefrontID()</code> method. Delete the line <code>print(json.rawString())</code> and replace it with the following</p>



<pre class="wp-block-code"><code>// 1
let result = (json[&quot;data&quot;]).array!
let id = (result[0].dictionaryValue)[&quot;id&quot;]!

// 2
storefrontID = id.stringValue

// 3
lock.signal()</code></pre>



<ol><li>We set <code>result</code> to be the array the JSON payload provides underneath the <code>data</code> key. <code>id</code> is simply value provided under the <code>id</code> key in the dictionary provided in <code>result</code>. This can sound a little confusing. The names of keys and values can be derived from the JSON string we printed earlier. To learn more about reading and parsing JSON, this [article][4] can help you.</li><li>We set the <code>storefrontID</code> to the string value of the <code>id</code> constant from Step 1.</li><li>Just like earlier, we signal the dispatch semaphore that it&#x2019;s okay to execute remaining code and free up the thread.</li></ol>



<p>Your entire <code>fetchStorefrontID()</code> method should look like this.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18439" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-9.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Run the app again and you&#x2019;ll see how instead of printing a JSON file, only two characters are printed, signifying the storefront ID of your Apple Music account. For me, in the United States, a simple &#x201C;us&#x201D; is printed out.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18440" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-10.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>If everything works, give yourself a pat on the back! We have one last method to implement in our <code>AppleMusicAPI</code> class and this one is pretty big. This method will allow us to search Apple Music&#x2019;s entire library of 40 million+ songs based on the keywords given. Now&#x2019;s a good time to take a break!</p>



<h2 class="wp-block-heading">Music Search</h2>



<p>Underneath our <code>fetchStorefrontID()</code> method, let&#x2019;s add a new method called <code>searchAppleMusic(searchTerm:)</code> that will let us search Apple Music&#x2019;s library based on the term. Here&#x2019;s a boilerplate to get you started. You&#x2019;ll notice it&#x2019;s very similar to our <code>fetchStorefrontID()</code> function.</p>



<pre class="wp-block-code"><code>func searchAppleMusic(_ searchTerm: String!) -&gt; [Song] {
    let lock = DispatchSemaphore(value: 0)
    var songs = [Song]()

    let musicURL = URL(string: &quot;https://api.music.apple.com/v1/catalog/\(fetchStorefrontID())/search?term=\(searchTerm.replacingOccurrences(of: &quot; &quot;, with: &quot;+&quot;))&amp;types=songs&amp;limit=25&quot;)!
    var musicRequest = URLRequest(url: musicURL)
    musicRequest.httpMethod = &quot;GET&quot;
    musicRequest.addValue(&quot;Bearer \(developerToken)&quot;, forHTTPHeaderField: &quot;Authorization&quot;)
        musicRequest.addValue(getUserToken(), forHTTPHeaderField: &quot;Music-User-Token&quot;)

    URLSession.shared.dataTask(with: musicRequest) { (data, response, error) in
        guard error == nil else { return }

    }.resume()

    lock.wait()
    return songs
}</code></pre>



<p>In terms of variables, we have our routine dispatch semaphore defined and a new <code>songs</code> array of type <code>Song</code> that we defined earlier. We&#x2019;ll be storing the songs in this array and returning this array to populate our table. You&#x2019;ll notice that <code>searchTerm</code> is a <code>String</code> provided as an input to this function. We also perform string manipulation on <code>searchTerm</code> to replace any instances of whitespaces with the <strong>+</strong> symbol as URL&#x2019;s can&#x2019;t contain any whitespaces.</p>



<p>We also create the <code>URLRequest</code> using the Apple Music API url. Notice that like before, it uses the root path <em>https://api.music.apple.com/v1/</em>. However, the URL component is <em>catalog</em> and we pass the search term as a parameter of the URL. Apart from these changes, we again use the GET request, create the request, and add our developer token to the header.</p>



<p>Now comes the important part which is parsing the data returned from our <code>URLSession.shared.dataTask</code>. Let&#x2019;s think about what we need. We need to parse the data for an array of songs. We then need to isolate the different components of the each song in the array such as title, artist, album artwork, etc. After isolating these components, we can create an object of type <code>Song</code> and add this to our <code>songs</code> array. This is how it can be accomplished. </p>



<p>Type the following code and place it underneath <code>guard error == nil else { return }</code> inside the <code>URLSession.shared.dataTask()</code> method:</p>



<pre class="wp-block-code"><code>// 1
if let json = try? JSON(data: data!) {
    // 2
    let result = (json[&quot;results&quot;][&quot;songs&quot;][&quot;data&quot;]).array!
    // 3
    for song in result {
        // 4
        let attributes = song[&quot;attributes&quot;]
        let currentSong = Song(id: attributes[&quot;playParams&quot;][&quot;id&quot;].string!, name: attributes[&quot;name&quot;].string!, artistName: attributes[&quot;artistName&quot;].string!, artworkURL: attributes[&quot;artwork&quot;][&quot;url&quot;].string!)
        songs.append(currentSong)
    }
    // 5
    lock.signal()
} else {
    // 6
    lock.signal()
}</code></pre>



<p>This is very similar to the code we wrote above to fetch a user&#x2019;s storefront ID. The only difference it there&#x2019;s a lot more JSON parsing and we are creating a <code>Song</code> object to add to our array.</p>



<ol><li>First, we type check to see is the data returned is in a valid JSON format. If it is, we create a constant called <code>json</code> containing all this data in the JSON file format.</li><li>We parse <code>json</code> for the songs that is nested within <code>results</code> -&gt; <code>songs</code> -&gt; <code>data</code> in an array format. Now, I don&#x2019;t want to burden you with more JSON formatting but this order was derived by printing the raw string of <code>json</code> and noticing how each component was ordered. If you want, you can print <code>json</code> to see how <code>result</code> is nested within the JSON data. <code>result</code> will now contain an array of our songs.</li><li>Now, we parse through each song in <code>result</code> using our trusty for loop.</li><li>First, we define a constant called <code>attributes</code> that is a dictionary of all the attributes of our current song. These attributes contain lots of information about the current song but we&#x2019;re interested in the id, name, artist&#x2019;s name, and artwork URL. Then we create a <code>currentSong</code> constant of type <code>Song</code> that is populated with the values from the <code>attributes</code> dictionary. Finally, we append the <code>currentSong</code> to our <code>songs</code> array.</li><li>Last but not least, we signal our dispatch semaphore through<code>lock</code> so the rest of the thread can be freed up to run the remaining code.</li><li>This is more of a check but if the data returned is not in a valid JSON format, we don&#x2019;t want our app to stay stuck forever. This is why we add an <code>else</code> clause to signal the dispatch semaphore to continue the rest of the code.</li></ol>



<p>Now we need to make sure our function works. Head over to <strong>ContentView.swift</strong>. In the <code>.onAppear()</code> declaration, we need to make a very minor change to the statement where we print <code>AppleMusicAPI().fetchStorefrontID()</code>. All we need to do is replace <code>.fetchStorefrontID()</code> with <code>.searchAppleMusic(&quot;Taylor Swift&quot;)</code>. If all goes well, when we run the app, this will print an array of <code>Song</code> objects containing all the songs Apple Music returns when its catalog is searched for <strong>Taylor Swift</strong>. (Of course, you can replace this with any artist, album, song, or word of your choice).</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18441" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-12.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Run the app and observe the console. After a few seconds, you should see an output similar to the following:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18442" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-13.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>As you can see, a whole array containing the songs based on your search term. We can look at the artist name, id, name of the song, and a URL to the album artwork. Since we know our code works, let&#x2019;s delete the entirety of the <code>.onAppear()</code> declaration. That way we don&#x2019;t necessarily make calls to the API when our app loads.</p>



<p>Now comes the second part of this section which is populating our search table view with the results.</p>



<h3 class="wp-block-heading">Populating the Table</h3>



<p>Go to <strong>SearchView.swift</strong>. We&#x2019;ll be making all the changes here to populate our search table. There are many changes we have to make so follow carefully.</p>



<p>First, we need to replace the <code>songs</code> array containing some temporary strings. Delete that line and replace it with the following line:</p>



<pre class="wp-block-code"><code>@State private var searchResults = [Song]()</code></pre>



<p>This creates a new empty array called <code>searchResults</code> that conforms to our <code>Song</code> object. We also link it to the <code>@State</code> property so anytime any changes are made to this array, any UI using this variable will be updated.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1920" height="1155" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18443" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14.png 1920w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-14-50x30.png 50w" sizes="(max-width: 1920px) 100vw, 1920px"></figure>



<p>Now, as expected, you&#x2019;ll get some errors since we removed our old <code>songs</code> array. Let&#x2019;s start at the <code>ForEach</code> within our <code>List</code> SwiftUI component. The error displayed here is that we&#x2019;re still trying to iterate over a variable <code>songs</code> that doesn&#x2019;t exist. Replace the <code>ForEach</code> line with the following:</p>



<pre class="wp-block-code"><code>ForEach(searchResults, id:\.id) { song in
    ...</code></pre>



<p>There are three changes we&#x2019;ve made here.</p>



<ol><li>The first change is we&#x2019;ve replaced <code>songs</code> which <code>searchResults</code>.</li><li>Now since our <code>Song</code> object doesn&#x2019;t conform to the <code>Hashable</code> property, we can&#x2019;t use <code>.self</code> to use it as an <code>id</code>. Good news though! Our <code>Song</code> objects have an <code>id</code> property to identify each element. This is why we replace <code>\.self</code> with <code>\.id</code>.</li><li>Finally, and this is really minor, we replace the <code>songTitle</code> variable to <code>song</code>. <code>songTitle</code> referred to the string from our old array. This isn&#x2019;t very representative of the current array for which we are iterating which is why we rename it to <code>song</code>.</li></ol>



<p>While this error is removed, we now have errors wherever we used the variable <code>songTitle</code>. This is a simple fix as we replace <code>songTitle</code> with <code>song.name</code>. Modify the code after the <code>Image</code> object within your <code>HStack</code> to look like the following:</p>



<pre class="wp-block-code"><code>VStack(alignment: .leading) {
    // 1
    Text(song.name)
        .font(.headline)
    // 2
    Text(song.artistName)
        .font(.caption)
        .foregroundColor(.secondary)
}
Spacer()
Button(action: {
    // 3
    print(&quot;Playing \(song.name)&quot;)
}) {
    Image(systemName: &quot;play.fill&quot;)
        .foregroundColor(.pink)
}</code></pre>



<ol><li>first change we made was to replace <code>songTitle</code> with <code>song.name</code>. This will use the name of the song as the string value for this Text object.</li><li>The second change we made is to replace the <strong>&#x201D;Artist Name&#x201D;</strong> placeholder with the actual artists name. Just like <code>song.name</code>, we use <code>song.artistName</code> to populate this <code>Text</code> object with the value in <code>song.artistName</code>.</li><li>Finally, the last change we made was a slight modification to our <code>Button</code> object which is to replace <code>songTitle</code> with <code>song.name</code> just like Step 1.</li></ol>



<p>Now, you can build and run the app. Everything should compile and work as normal but there&#x2019;s a catch. You&#x2019;ll notice that when you search for a song and press enter, nothing happens. This is because we still haven&#x2019;t called the <code>searchAppleMusic</code> function from our <code>AppleMusicAPI()</code> class. To do this, we need to make some changes to our <code>TextField</code>. Before this, at the top of the file underneath <code>import SwiftUI</code>, add the line <code>import StoreKit</code>.</p>



<p>Now, make the following changes to your <code>TextField</code>:</p>



<pre class="wp-block-code"><code>TextField(&quot;Search Songs&quot;, text: $searchText, onCommit: {
    // 1
    UIApplication.shared.resignFirstResponder()
    if self.searchText.isEmpty {
        // 2
        self.searchResults = []
    } else {
        // 3
        SKCloudServiceController.requestAuthorization { (status) in
            if status == .authorized {
                // 4
                self.searchResults = AppleMusicAPI().searchAppleMusic(self.searchText)
            }
        }
    }
})
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.horizontal, 16)
.accentColor(.pink)</code></pre>



<p>We&#x2019;re at the last stretch here but this code shouldn&#x2019;t be too complicated for you to read. Here&#x2019;s a gist of what it compiles:</p>



<ol><li>First, we&#x2019;d like to dismiss the keyboard when the user presses <strong>Search</strong> on the keyboard. This is done by calling the line <code>UIApplication.shared.resignFirstResponder()&amp;nbsp;</code>.</li><li>Next, we&#x2019;d like to make sure that if the user doesn&#x2019;t enter anything, our <code>searchResults</code> are empty. This is why we set it to an empty array if the <code>searchText</code> is empty.</li><li>If the <code>searchText</code> variable is not empty, we&#x2019;d like to call our <code>searchAppleMusic</code> function. Before we do this, we make sure that <code>SKCloudServiceController</code> has the necessary authorization to access a user&#x2019;s media library. If the user authorizes this access, we can continue to the next line of code.</li><li>Finally, we set out <code>searchResults</code> array equal to the results of <code>AppleMusicAPI().searchAppleMusic(self.searchText)</code>. This will pass the search term to our <code>searchAppleMusic</code> function and update our <code>searchResults</code> array with whatever Apple Music returns!</li></ol>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18444" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-16.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>We&#x2019;re finally ready to run our app. Build and run the app and head over to the Search page. Enter any term, wait for a couple seconds as your app makes network requests you&#x2019;ve implemented, and watch with delight as the table view is populated with the results of your search term.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1920" height="689" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18445" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17.png 1920w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-600x215.png 600w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-1024x367.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-200x72.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-768x276.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-1536x551.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-1680x603.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-1240x445.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-860x309.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-680x244.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-400x144.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-17-50x18.png 50w" sizes="(max-width: 1920px) 100vw, 1920px"></figure>



<p>Congratulations! You&#x2019;ve mastered the basics of the Apple Music API! As you can see, it&#x2019;s very repetitive in that the steps can be summed down to the following:</p>



<ol><li>Make a network call to the Apple Music API</li><li>Parse the JSON to see where the data you need can be found</li><li>Create an object and populate it with the data you&#x2019;ve parsed</li></ol>



<p>For the remainder of the tutorial, we&#x2019;ll be focusing on the under appreciated <code>MediaPlayer</code> framework and its very important object, <code>MPMusicPlayerController&amp;nbsp;</code>. Also, don&#x2019;t worry about the album artwork not displaying as of now. I&#x2019;ll show you how we can use <strong>Swift Package Manager</strong> to successfully load and display images from a URL.</p>



<h2 class="wp-block-heading">Implementing Music Play Back</h2>



<p>Get excited because now we&#x2019;ll be looking at the <code>MediaPlayer</code> framework and how to access and control your device&#x2019;s music player. Essentially, the <code>MediaPlayer</code> framework is a part of MusicKit and lets you control playback of the user&#x2019;s media from your app.</p>



<p>To play content using this framework, we have to instantiate one of the built-in <code>MPMusicPlayerController</code> objects. There are two types. Here is a brief description of what they are:</p>



<ol><li><strong>System Player</strong>: This media player is directly linked to the Music app on your device. If you choose to use this player, then when a user click on a song, it will open up Music and start playing from that app.</li><li><strong>Application Player</strong>: This will be a media player that is built-in directly to your app. That way when a user clicks on a song, they won&#x2019;t be transported to the Music app, but rather all the playback functionality will occur in your app. Of course, this means that you will have to add play/pause and skip/rewind functionality. We&#x2019;ll be using this type of player for our app.</li></ol>



<p>Let&#x2019;s add the application player to our app. Now we want to modify this object within both screens of our app. In our <strong>Player View</strong>, we want to control the playback of the currently playing item in the song and in our <strong>Search View</strong>, we want to be able to play songs directly from that page. As such, we&#x2019;ll be implementing <code>@State</code> and <code>@Binding</code> protocols to help with data flow.</p>



<p>Head over to <strong>ContentView.swift</strong>. At the top of the file, type <code>import MediaPlayer</code> underneath <code>import StoreKit</code>. Next, add the following line where you declare your <code>selection</code> variable:</p>



<pre class="wp-block-code"><code>@State private var musicPlayer = MPMusicPlayerController.applicationMusicPlayer</code></pre>



<p>We&#x2019;re creating a variable called <code>musicPlayer</code> that is of the type <code>applicationMusicPlayer</code> as we discussed above. We&#x2019;re also adding the <code>@State</code> property to it so we can use it to pass it to other views. Let&#x2019;s do that right now!</p>



<p>Go to <strong>PlayerView.swift</strong> and at the top of the file, add import the <code>MediaPlayer</code> framework with:</p>



<pre class="wp-block-code"><code>import MediaPlayer</code></pre>



<p>Next, at the top of the<code>struct</code>, add the following line:</p>



<pre class="wp-block-code"><code>@Binding var musicPlayer: MPMusicPlayerController</code></pre>



<p>This creates a <code>Binding</code> variable for our <strong>Player View</strong>. Since we will be binding this variable to the <code>musicPlayer</code> we created in <strong>ContentView.swift</strong>, anytime we make a change in <strong>Player View</strong> to this object, it will be reflected in <strong>Content View</strong>.</p>



<p>Since we can&#x2019;t pass this binding variable to our <code>PlayerView_Previews</code> and SwiftUI previews have no support for MusicKit, there&#x2019;s no point in having this in our file anymore. Delete the entire <code>PlayerView_Previews</code> structure from this file.</p>



<p>Let&#x2019;s do the same thing in <strong>SearchView.swift</strong>. You should already have the <code>MediaPlayer</code> framework implemented. Just like before, add the following line to the top of your <code>SearchView</code> structure below the initialization of the <code>searchResults</code> array.</p>



<pre class="wp-block-code"><code>@Binding var musicPlayer: MPMusicPlayerController</code></pre>



<p>Similar to <strong>PlayerView.swift</strong>, delete the entire <code>SearchView_Previews</code> structure from this file.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18446" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-20.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Now, head back to <strong>ContentView.swift</strong>. You should see some errors for <code>PlayerView()</code> and <code>SearchView()</code>. This is simply because we haven&#x2019;t added the argument for the parameter <code>musicPlayer</code> when we call it. You can fix this by changing <code>PlayerView()</code> to <code>PlayerView(musicPlayer: self.$musicPlayer)</code> and <code>SearchView()</code> to <code>SearchView(musicPlayer: self.$musicPlayer)</code>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18447" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-21.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Build the app! It should compile without errors. We now have a built-in media player that is accessible to all the views in our app! Now when we implement the play and pause methods, we can easily update our player and reflect those changes across all the views in our app!</p>



<h3 class="wp-block-heading">Playing Music</h3>



<p>When our user clicks on a song from the search table, we&#x2019;d like our app to play the song selected. This means that we have to add a song to our <code>musicPlayer</code>&#x2019;s queue and tell the queue to play. Watch how we implement this in two line!</p>



<p>Go to <strong>SearchView.swift</strong>. Find the <code>Button</code> structure that should be inside the <code>List</code> structure. As of right now, it only prints the name of the song it is playing to the console. Delete that line and replace it with the following:</p>



<pre class="wp-block-code"><code>self.musicPlayer.setQueue(with: [song.id])
self.musicPlayer.play()</code></pre>



<p>That&#x2019;s it! In the first line, we set the queue of our <code>musicPlayer</code>. The queue in this case is an array of strings containing the ID&#x2019;s of the song. This is why the <code>MediaPlayer</code> and Apple Music API work harmoniously together. The framework can automatically detect which song is to be played based on the ID given. The final line simply instructs our <code>musicPlayer</code> to play whatever is in the queue!</p>



<p>Build and run the app! You should be able to search for a song, and when you tap on it, your music player should start playing the song!</p>



<p>If you&#x2019;ve got everything working, congratulations! This is one of the most under appreciated, unknown functionalities you can build using Swift! We&#x2019;re not done yet though! While we can play music, we&#x2019;d also like to control the playback state of the song! We also want to make sure that the <strong>Player View</strong> can show us the name of the song and tag artist&#x2019;s name. This can be achieved relatively simply as well!</p>



<p>Go to <strong>PlayerView.swift</strong>. Let&#x2019;s start at the top of the file and make the respective changes as we work our way down!</p>



<p>Find the <code>VStack</code> structure where we define our <code>Text</code> objects that will contain the name of the song and the artist&#x2019;s name. Replace it with the following:</p>



<pre class="wp-block-code"><code>VStack(spacing: 8) {
    Text(self.musicPlayer.nowPlayingItem?.title ?? &quot;Not Playing&quot;)
        .font(Font.system(.title).bold())
    Text(self.musicPlayer.nowPlayingItem?.artist ?? &quot;&quot;)
        .font(.system(.headline))
}</code></pre>



<p>The changes we&#x2019;ve made here is to replace &#x201C;Song Title&#x201D; and &#x201C;Artist Name&#x201C; with the actual name of the currently playing song and the artist by whom it&#x2019;s sung. If no song is playing, then we leave the artist&#x2019;s name empty and set the name of the song to <strong>&#x201D;Not Playing&#x201D;</strong>.</p>



<p>Before we go further, I&#x2019;d like to explain a little bit about this <code>.nowPlayingItem</code> object we&#x2019;re calling. This object is of a type called <code>MPMediaItem</code>. This object is provided by the <code>MediaPlayer</code> framework and is an object which contains a collection of properties that represents what you could call a &#x201C;song&#x201D; in a media library. More specifically, an <code>MPMediaItem</code> can be any object that can be played and has a metadata that is similar to any audio-based object such as a song or podcast. The properties we&#x2019;re using here are <code>title</code>, which is the name of the song, and <code>artist</code>, which is the name of the artist. There are many more properties that you can use if you choose to that can be found <a href="https://developer.apple.com/documentation/mediaplayer/mpmediaitem?ref=appcoda.com" class="rank-math-link">here</a>.</p>



<p>Build and run your app. You can see that when you start to play a song, the metadata is displayed where it&#x2019;s supposed to be!</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1920" height="1853" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18448" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24.png 1920w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-311x300.png 311w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-1024x988.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-200x193.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-768x741.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-1536x1482.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-1680x1621.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-1240x1197.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-860x830.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-680x656.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-400x386.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-24-50x48.png 50w" sizes="(max-width: 1920px) 100vw, 1920px"></figure>



<p>Now, let&#x2019;s add some play and pause functionality. Scroll down in <strong>PlayerView.swift</strong> and go to the <code>Button</code> object which currently prints <strong>&#x201D;Pause&#x201D;</strong> to the console. Delete this line and replace it with the following:</p>



<pre class="wp-block-code"><code>if self.musicPlayer.playbackState == .paused || self.musicPlayer.playbackState == .stopped {
    self.musicPlayer.play()
} else {
    self.musicPlayer.pause()
}</code></pre>



<p>Our <code>musicPlayer</code> has a property called <code>playbackState</code> that is of type <code>MPMusicPlaybackState</code>. This property keeps track of whether the music player is playing a song, paused, or stopped. If the <code>playbackState</code> is equal to<code>.paused</code> or <code>.stopped</code>, then nothing is playing and when the user clicks on this button, we&#x2019;d like for it to start playing. This is why we call <code>self.musicPlayer.play()</code>. Similarly, in the else clause, we call <code>self.musicPlayer.pause()</code> because we&#x2019;d like to stop the currently playing song.</p>



<p>You can build and run the app on your device. You should see that when you click on the pause button, the music pauses and when you press again, the music resumes. However, the icon of the button is not updating. This can be done by tracking the playback state of the currently playing item!</p>



<p>At the top of <strong>PlayerView.swift</strong>, underneath where you declared <code>musicPlayer</code>, type the following line:</p>



<pre class="wp-block-code"><code>@State private var isPlaying = false</code></pre>



<p>This is a Boolean variable that is attached to the <code>@State</code> property that will be updated based on the playback state of the currently playing song. First, go to the <code>Button</code> object we modified above. Modify the action of the <code>Button</code> to look like the following:</p>



<pre class="wp-block-code"><code>if self.musicPlayer.playbackState == .paused || self.musicPlayer.playbackState == .stopped {
    self.musicPlayer.play()
    // 1
    self.isPlaying = true
} else {
    self.musicPlayer.pause()
    // 2
    self.isPlaying = false
}</code></pre>



<p>We&#x2019;ve added two lines that are pretty self explanatory. When we signal the <code>musicPlayer</code> to play, we set the <code>isPlaying</code> variable to <code>true</code>. When we pause the <code>musicPlayer</code>, we once again set the <code>isPlaying</code> variable to <code>false</code>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18449" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-26.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Next, we need to use the <code>isPlaying</code> variable to update the image used as the logo for the button. This is quite simple. Underneath the button&#x2019;s action where we declare the UI of the button, modify the <code>ZStack</code> object to look as such:</p>



<pre class="wp-block-code"><code>ZStack {
    Circle()
        .frame(width: 80, height: 80)
        .accentColor(.pink)
        .shadow(radius: 10)
    Image(systemName: self.isPlaying ? &quot;pause.fill&quot; : &quot;play.fill&quot;)
        .foregroundColor(.white)
        .font(.system(.title))
}</code></pre>



<p>The change we made here is to change the <code>systemName</code>of the <code>Image</code> object used based on whether <code>self.isPlaying</code> is true or false. If it is true, we&#x2019;ll use the <strong>pause.fill</strong> SF Symbol. If not, we&#x2019;ll use the <strong>play.fill</strong> symbol.</p>



<p>Last but not least, we need a way to update <code>self.isPlaying</code> if there is a change made in <strong>Search View</strong>. For example, if our player is paused but we play a song from <strong>Search View</strong>, we&#x2019;d like to update <code>self.isPlaying</code> by setting it to true. Now, we can use the <code>@Binding</code> protocol but I&#x2019;d like to show you an easier alternative: the <code>onAppear()</code> function!</p>



<p>At the very bottom of <strong>PlayerView.swift</strong>, find the second to last <strong>}</strong> closing curly bracket. This is the bracket that will close our <code>GeometryReader</code>. Attach the <code>.onAppear()</code> function below it as shown:</p>



<pre class="wp-block-code"><code>.onAppear() {
    if self.musicPlayer.playbackState == .playing {
        self.isPlaying = true
    } else {
        self.isPlaying = false
    }
}</code></pre>



<p>What are we doing in this function? Well, remember that our <code>musicPlayer</code> is already bound to all the views in our app. So any updates to this object is immediately reflected in every view. When we play a song from <strong>Search View</strong>, the <code>musicPlayer</code> is updated to set its <code>playbackState</code> to <code>.playing</code>. This is why in the <code>.onAppear()</code> function, we check to see that if the <code>playbackState</code> is in fact playing, then we set <code>isPlaying</code> to true. If not, we set <code>isPlaying</code> to false!</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18450" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-28.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>That&#x2019;s all for playing and pausing! Build and run your app! You should see that the play/pause button accurately changes based on whether the song is currently playing or is paused!</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1920" height="1853" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18451" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29.png 1920w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-311x300.png 311w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-1024x988.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-200x193.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-768x741.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-1536x1482.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-1680x1621.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-1240x1197.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-860x830.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-680x656.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-400x386.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-29-50x48.png 50w" sizes="(max-width: 1920px) 100vw, 1920px"></figure>



<h2 class="wp-block-heading">Implementing Skip &amp; Rewind</h2>



<p>Now let&#x2019;s implement the logic for skip and rewind buttons. This won&#x2019;t take too long. Let&#x2019;s start with the skip button.</p>



<p>Navigate to <strong>PlayerView.swift</strong> and locate the <code>Button</code> object that we&#x2019;re using as a temporary skip button. It should be printing <strong>&#x201D;Skip&#x201D;</strong> to the console when tapped upon.</p>



<p>Replace the line <code>print(&quot;Skip&quot;)</code> with <code>self.musicPlayer.skipToNextItem()</code> and that&#x2019;s all! Build and run your app. When you press the skip button, it will jump to the next song in the queue, which is nothing, so the player will stop!</p>



<p>You can see how <code>MediaPlayer</code> comes with a list of functions that make it easy for us to control playback! With one line of code, we were able to implement a &#x201C;skip song&#x201D; functionality into our music player app. The &#x201C;rewind&#x201D; button is a little more challenging.</p>



<p>Think about your favorite music player. When you press the rewind button, what happens? If the song is more than 5 seconds through its playback, it skips to the beginning of the song. If the current playback is still within the first 5 seconds, then it goes to the previous song. With a simple <code>if-else</code> statement, watch how we can add the same functionality to our app.</p>



<p>Scroll back up to the <code>Button</code> object that currently prints <strong>&#x201D;Rewind&#x201D;</strong> to the console. Delete that line and replace it with the following:</p>



<pre class="wp-block-code"><code>if self.musicPlayer.currentPlaybackTime &lt; 5 {
    self.musicPlayer.skipToPreviousItem()
} else {
    self.musicPlayer.skipToBeginning()
}</code></pre>



<p>You can see that we use a new property here: <code>currentPlaybackTime</code>. This is the length of the song, in seconds, that has been played by our player. If the number of seconds played so far is less than 5, we call upon a new method: <code>skipToPreviousItem()</code>. This method, provided by the <code>MediaPlayer</code> framework, we jump back in the queue and start playing the song before this song. Currently, this will continue playing the beginning of this song.</p>



<p>However, what we can test is that if <code>currentPlaybackTime</code> is greater than or equal to 5, we can call <code>skipToBeginning()</code> in our <code>musicPlayer</code> and that will ask our <code>musicPlayer</code> to start playing from the beginning of our current song.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18452" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-31.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Build and run your app! It should be able to handle the skip and rewind buttons as you implemented! As you can see from this section, a lot of the methods we use to control playback are already implemented in the <code>MediaPlayer</code> framework. With a little research, you can continue to build upon all these features.</p>



<h2 class="wp-block-heading">Implementing Album Artwork</h2>



<p>Finally, let&#x2019;s replace the ugly &#x201C;A&#x201D; SF Symbol with the album artwork of the current song playing. If you remember from earlier, our <code>Song</code> object has a property called <code>artworkURL</code> that contains the string of a URL containing the image of the album.</p>



<p>Normally, we&#x2019;d have to write a lot of code to process the URL, gather the image data, and cache the image so we wouldn&#x2019;t make redundant calls. I&#x2019;d like to show you a nifty Swift package called [SDWebImageSwiftUI][6]. This package contains a framework built for SwiftUI that can help with image loading and contains features like async image loading, memory/disk caching, animated image playback and more. If you ever need to load images from a URL in your apps, I highly recommend this framework since it automatically handles image loading and caching, thereby speeding up your app.</p>



<p>Here&#x2019;s how we can install it. We&#x2019;ll be using <strong>Swift Package Manager</strong> to link this framework with our project. In Xcode, go to the Title Bar, and click on File &gt; Swift Packages &gt; Add Package Dependancy.</p>



<p></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="640" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-1024x640.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18453" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-1024x640.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-480x300.png 480w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-200x125.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-768x480.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-1536x960.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-1680x1050.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-1240x775.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-860x538.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-680x425.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-400x250.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32-50x31.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-32.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>A popup will show up and ask you to enter a package repository URL. The URL we will be using is <a href="https://github.com/SDWebImage/SDWebImageSwiftUI?ref=appcoda.com" class="rank-math-link">https://github.com/SDWebImage/SDWebImageSwiftUI</a>. Enter this URL and press <strong>Next</strong>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18454" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-33.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>After some loading, Xcode will ask you which version to use. Don&#x2019;t make any changes and simple press <strong>Next</strong>. Xcode will take some time to fetch the repository and create a package to add to your project. After a minute, Xcode will show you a popup confirming you to choose the packages and target. Make sure it looks like something below.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18455" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-34.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>The important point to follow here is that <strong>MusicPlayer</strong> is selected as the target. Click <strong>Finish</strong> and Xcode will take you to the main project page that shows all your Swift Packages. This means that the package has successfully been added to your project and you can start using the framework!</p>



<p>Go to <strong>SearchView.swift</strong> and at the top of the file, type <code>import SDWebImageSwiftUI</code>. This will gives us access to all the objects and methods in this framework.</p>



<p>In our <strong>List</strong> object, locate the <strong>Image</strong> object that is currently coded as such:</p>



<pre class="wp-block-code"><code>Image(systemName: &quot;rectangle.stack.fill&quot;)
    .resizable()
    .frame(width: 40, height: 40)
    .cornerRadius(5)
    .shadow(radius: 2)</code></pre>



<p>Making sure that all its modifiers are still in place, replace it with the following</p>



<pre class="wp-block-code"><code>WebImage(url: URL(string: song.artworkURL.replacingOccurrences(of: &quot;{w}&quot;, with: &quot;80&quot;).replacingOccurrences(of: &quot;{h}&quot;, with: &quot;80&quot;)))
    .resizable()
    .frame(width: 40, height: 40)
    .cornerRadius(5)
    .shadow(radius: 2)</code></pre>



<p><code>SDWebImageSwiftUI</code> provides an object called <code>WebImage</code>. This is very similar to our <code>Image</code> object but has some really neat additions. For one, it takes an argument called <code>url</code> which when provided, automatically loads the image from this URL.</p>



<p>We create a <code>URL</code> object and pass the string <code>song.artworkURL</code>. Notice that once again, we perform string manipulation here. If you notice the URL, you&#x2019;ll notice that it has two parameters: <strong>{h}</strong> and <strong>{w}</strong>. These parameters stand for height and width, respectively. This is provided by the Apple Music API on purpose because we can specify the height and width that is best suited for us. I chose a height and width of 80, since this is 2x the size of our <code>WebImage</code> so the image loaded will have a high quality. Therefore, we call <code>replaceOccurences</code> on both <strong>{w}</strong> and <strong>{h}</strong> and replace it with 80.</p>



<p>Everything else should remain the same! Make sure your code looks like the screenshot below:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18456" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-36.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Build and run your app! Now, when you search for a song, you can actually see the album cover in the search results. The best part too is that <code>SDWebImageSwiftUI</code> caches the image so if you quit the app and search for the same term again, you can notice that there is a huge speed increase in loading the image.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1920" height="1227" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18457" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37.png 1920w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-469x300.png 469w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-1024x654.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-200x128.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-768x491.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-1536x982.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-1680x1074.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-1240x792.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-860x550.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-680x435.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-400x256.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-37-50x32.png 50w" sizes="(max-width: 1920px) 100vw, 1920px"></figure>



<p>Our last step is to change the album artwork in <strong>PlayerView.swift</strong>. Unfortunately, this is not as simple. See, in <strong>SearchView.swift</strong> we had a list of <code>Song</code> objects, each containing a URL to the album cover. Since we didn&#x2019;t pass this list along, our <strong>Player View</strong> can&#x2019;t access this album artwork URL. Furthermore, while <code>MediaPlayer</code> is great at providing many built-in objects and methods, it does not contain an object with a link to a particular song&#x2019;s album artwork.</p>



<p>In order to fix this, we need to rely on <code>State</code> and <code>Binding</code>, once again. Head to <strong>ContentView.swift</strong> and at the top of the file, underneath where you created your <code>musicPlayer</code> variable, add the following file:</p>



<pre class="wp-block-code"><code>@State private var currentSong = Song(id: &quot;&quot;, name: &quot;&quot;, artistName: &quot;&quot;, artworkURL: &quot;&quot;)</code></pre>



<p>We are creating a new shared object called <code>currentSong</code> of type <code>Song</code> that will be updated whenever we click on a new song from our <strong>Search View</strong>.</p>



<p>On that note, go to <strong>SearchView.swift</strong> and add the following <code>Binding</code> property at the top of the file, below where you declared your <code>musicPlayer</code> variable.</p>



<pre class="wp-block-code"><code>@Binding var currentSong: Song</code></pre>



<p>Scroll to the bottom of the file and you&#x2019;ll find the <code>Button</code> object that currently sets the queue of the <code>musicPlayer</code> and tells it to start playing. Over here, we want to set <code>currentSong</code> to the song that was tapped upon.</p>



<p>Modify the action of the <code>Button</code> as shown.</p>



<pre class="wp-block-code"><code>Button(action: {
    self.currentSong = song
    self.musicPlayer.setQueue(with: [song.id])
    self.musicPlayer.play()
})</code></pre>



<p>All we&#x2019;re adding here is setting the <code>currentSong</code> to the <code>song</code> that was tapped on.</p>



<p>Let&#x2019;s do the same for <strong>PlayerView.swift</strong>. Navigate to that file and at the very top, add <code>import SDWebImageSwiftUI</code>. This will let us use the <code>WebImage</code> object as we did above.</p>



<p>Next, add the <code>Binding</code> variable <code>currentSong</code> to the structure, right below where we declared the <code>isPlaying</code> variable.</p>



<pre class="wp-block-code"><code>@Binding var currentSong: Song</code></pre>



<p>Last but not least, let&#x2019;s replace our current <code>Image</code> object which holds the SF Symbol <strong>a.square</strong> with the following code. Notice that all the modifiers remain the same.</p>



<pre class="wp-block-code"><code>WebImage(url: URL(string: self.currentSong.artworkURL.replacingOccurrences(of: &quot;{w}&quot;, with: &quot;\(Int(geometry.size.width - 24) * 2)&quot;).replacingOccurrences(of: &quot;{h}&quot;, with: &quot;\(Int(geometry.size.width - 24) * 2)&quot;)))
    .resizable()
    .frame(width: geometry.size.width - 24, height: geometry.size.width - 24)
    .cornerRadius(20)
    .shadow(radius: 10)</code></pre>



<p>Now just like before, we pass a URL to <code>WebImage</code>, only this URL is very lengthy. Just like before, we are replacing <strong>{w}</strong> and <strong>{h}</strong> with the width and height we want. It&#x2019;s not as simple as before however, since our height and width is reliant on the width of the device. This is why we replace <strong>{w}</strong> and <strong>{h}</strong> with <code>geometry.size.width - 24</code>. The number is actually of type <strong>Float</strong>so to convert it to an integer, we wrap it around in <code>Int</code>. Finally, we multiply both lengths by 2 to get a sharper image quality.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-1024x616.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18458" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-40.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Last but not least, we still need to pass the <code>currentSong</code> from our <strong>Content View</strong> to both the <strong>Player View</strong> and <strong>Search View</strong>. Head over to <strong>ContentView.swift</strong> and make the following changes to where you declare both <code>PlayerView()</code> and <code>SearchView()</code>.</p>



<pre class="wp-block-code"><code>PlayerView(musicPlayer: self.$musicPlayer, currentSong: self.$currentSong)
...
SearchView(musicPlayer: self.$musicPlayer, currentSong: self.$currentSong)</code></pre>



<p>In these changes, we passing the <code>currentSong</code> that was created in <code>ContentView.swift</code> to the remaining views.</p>



<p>Congratulations! This is the end of this lengthy tutorial! Build and run your app and watch with delight as your app can make calls to the Apple Music API, parse JSON and display a list of songs, utilize a devices media player capabilities to play songs and control playback, and harness external libraries to load images from remote sources- all using SwiftUI, a technology that is only a year old!</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1920" height="917" src="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42.png" alt="Using MusicKit and Apple Music API to Build a Music Player" class="wp-image-18459" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42.png 1920w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-600x287.png 600w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-1024x489.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-200x96.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-768x367.png 768w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-1536x734.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-1680x802.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-1240x592.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-860x411.png 860w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-680x325.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-400x191.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/musickit-player-42-50x24.png 50w" sizes="(max-width: 1920px) 100vw, 1920px"></figure>



<h2 class="wp-block-heading">Conclusion</h2>



<p>If you&#x2019;ve reached the end successfully, congratulations! This two part tutorial was not your average, intermediate tutorial. Despite its lengthy content, I hope you learned something new from all the technologies we&#x2019;ve utilized. I&#x2019;ve compiled a list of resources below that can help you if you choose to continue building upon this app! You can <a href="https://github.com/appcoda/MusicKitPlayer?ref=appcoda.com" class="rank-math-link">download the completed project</a> on GitHub.</p>



<p>For reference, you can check out the following resource related to this tutorial:</p>



<p><strong>Apple Documentation and Videos</strong></p>



<ul><li><a href="https://developer.apple.com/documentation/applemusicapi/?ref=appcoda.com" class="rank-math-link">Apple Music API Documentation</a></li><li><a href="https://developer.apple.com/documentation/storekit/?ref=appcoda.com" class="rank-math-link">StoreKit Documentation</a></li><li><a href="https://developer.apple.com/documentation/mediaplayer/?ref=appcoda.com" class="rank-math-link">MediaPlayer Documentation</a></li><li><a href="https://developer.apple.com/musickit/?ref=appcoda.com" class="rank-math-link">MusicKit on Android and the Web</a></li><li><a href="https://developer.apple.com/videos/play/wwdc2017/502/?ref=appcoda.com" class="rank-math-link">WWDC 2017 Video- Introduction MusicKit</a></li><li><a href="https://developer.apple.com/videos/play/wwdc2018/506/?ref=appcoda.com" class="rank-math-link">WWDC 2018 Video- MusicKit on the Web</a></li></ul>



<p><strong>More on the Technology</strong></p>



<ul><li><a href="https://www.json.org/json-en.html?ref=appcoda.com" class="rank-math-link">Introducing JSON</a></li><li><a href="https://www.appcoda.com/json-codable-swift/" class="rank-math-link">Working with JSON and Codable in Swift 5</a></li><li><a href="https://www.appcoda.com/learnswiftui/swiftui-state.html" class="rank-math-link">More on @State and @Binding in SwiftUI</a></li></ul>



<p>As always, if you have any doubts, feel free to leave a comment below or reach me on Twitter <a href="https://twitter.com/HeySaiK?ref=appcoda.com" class="rank-math-link">@HeySaiK</a>. I can&#x2019;t wait to see what you&#x2019;ll make with MusicKit!</p>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[Using LinkPresentation Framework to Present Rich Links in iOS Apps]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>While I&#x2019;ve introduced you quite a number of <a href="https://www.appcoda.com/xcode-12-swift-53/" class="rank-math-link">new features announced in WWDC 2020</a>. Let&#x2019;s step back a bit and check out a <a href="https://developer.apple.com/videos/play/wwdc2019/262/?ref=appcoda.com" class="rank-math-link">useful framework introduced</a> in WWDC 2019. At first glance, it does not look as significant or important as other frameworks, however it consists</p>]]></description><link>https://www.appcoda.com/linkpresentation-framework/</link><guid isPermaLink="false">66612a0f166d3c03cf0114d4</guid><category><![CDATA[iOS Programming]]></category><dc:creator><![CDATA[Gabriel Theodoropoulos]]></dc:creator><pubDate>Thu, 16 Jul 2020 15:30:59 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2020/07/vnfqkxcscru.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2020/07/vnfqkxcscru.jpg" alt="Using LinkPresentation Framework to Present Rich Links in iOS Apps"><p>While I&#x2019;ve introduced you quite a number of <a href="https://www.appcoda.com/xcode-12-swift-53/" class="rank-math-link">new features announced in WWDC 2020</a>. Let&#x2019;s step back a bit and check out a <a href="https://developer.apple.com/videos/play/wwdc2019/262/?ref=appcoda.com" class="rank-math-link">useful framework introduced</a> in WWDC 2019. At first glance, it does not look as significant or important as other frameworks, however it consists of a really useful tool when it is needed. That is the <strong>LinkPresentation</strong> framework, and it provides a handful of built-in functionalities that makes presenting rich links in apps a really simple and straightforward process.</p>



<p>LinkPresentation framework contains mechanisms that <em>parse</em> the website behind a link and fetch <em>metadata</em> necessary in order to display the link in a visually formatted, beautiful manner. In particular, it fetches the title, icon, images, and video metadata, when any of those is provided by the website through the <a href="https://ogp.me/?ref=appcoda.com">Open Graph protocol</a>.</p>



<p>Fetched metadata can be saved locally for future use, so it&#x2019;s possible to avoid downloading the exact same data repeatedly. Making the local storage of metadata (caching) a reality is assisted by the custom type that represents metadata programmatically; the <code>LPLinkMetadata</code> class, which is <em>serializable</em>, so it&#x2019;s easy to create Data objects out of it that can be written locally.</p>



<p>But the above are not the only features available. LinkPresentation also handles the appearance of a visually formatted link by providing a custom view configured based on fetched metadata, and that view also supports user interaction through single tap and long press gestures.</p>



<p>If there&#x2019;s just one negative point we can spot in the LinkPresentation framework, then that is the fact that it&#x2019;s built for UIKit (and AppKit on macOS), so integrating it in SwiftUI projects requires some additional work. But no need to worry, as in this post we&#x2019;ll do exactly this; we&#x2019;ll build a SwiftUI project where we&#x2019;ll embed and use the LinkPresentation framework!</p>



<p>LinkPresentation framework works in both iOS and macOS, starting from iOS 13 and macOS 10.15. Besides than fetching metadata for remote links, it&#x2019;s also possible to deal with links pointing to local files, however that&#x2019;s not something we&#x2019;ll discuss in this tutorial. We&#x2019;ll see all the main features that were presented shortly right above, and on top of that we&#x2019;ll see how LinkPresentation framework can be combined with the <em>activity view controller</em> in order to share links easily, taking advantage of already cached metadata.</p>



<p>So, keep on reading to find out some cool features of the LinkPresentation framework, but before that, let&#x2019;s meet the demo application we&#x2019;re going to build in the next parts of this tutorial!</p>



<h2 class="wp-block-heading">The Demo Application</h2>



<p>Our journey to LinkPresentation framework will take place using a SwiftUI based iOS application. Parts of it have already been built and you can <a href="https://github.com/appcoda/LinkPresentationDemo/blob/master/starter.zip?ref=appcoda.com" class="rank-math-link">download it here</a> as a starter project. Our work in this tutorial will begin by keep building on that starter project, so once you get it open it in Xcode.</p>



<p>In the demo application we&#x2019;ll go through all features of the LinkPresentation framework that one would need to incorporate in their own apps. The first thing we&#x2019;ll meet is how to fetch remote link metadata using the <code>LPMetadataProvider</code> class, and this will happen after having typed or pasted a URL in the <code>InputLinkView</code> view of the starter project.</p>



<p>Next, we&#x2019;ll see how to display a rich link after having fetched its metadata, and we&#x2019;ll get to know the <code>LPLinkView</code> class; the one that&#x2019;s responsible for presenting a link visually formatted. We&#x2019;ll display our first link view in the <code>InputLinkView</code> as the result of the link metadata fetching. In this part we&#x2019;ll have the opportunity to see how to bring a UIKit view to SwiftUI with the <code>UIViewRepresentable</code> protocol.</p>



<p>After that, we&#x2019;ll add the capability to save downloaded link metadata as part of a collection of links, and then load them. We&#x2019;ll talk about serialization, the <code>NSSecureCoding</code> protocol, and we&#x2019;ll archive and unarchive using the <code>NSKeyedArchiver</code> and <code>NSKeyedUnarchiver</code> classes respectively.</p>



<p>By making our app capable of caching link metadata locally and loading back we&#x2019;ll move on and we&#x2019;ll display all stored links in a list. This will happen in the <code>LinksListView</code> view, and once again, we&#x2019;ll make use of the link view.</p>



<p>Finally, we&#x2019;ll disable the default interactions with the link view and we&#x2019;ll implement our own <em>activity view controller</em> for sharing links in order to feed it with cached metadata; we&#x2019;ll prevent it that way from fetching that metadata again, which is its default behaviour. We&#x2019;ll meet a specific method of the <code>UIActivityItemSource</code> protocol that actually provides link metadata to activity view controller, and besides that some other intersting stuff, such as how to use a UIKit view controller in SwiftUI with the <code>UIViewControllerRepresentable</code> protocol.</p>



<p>In addition to all the above we&#x2019;ll make use of two additional custom types: The <code>Link</code> class which will represent a link programmatically, and the <code>LinksModel</code> which already contains a collection of <code>Link</code> objects and it consists of the place where we&#x2019;ll add all the implementation about fetching link metadata, saving and loading.</p>



<p>Navigate through the current implementation of the starter project, and when you&#x2019;re done, prepare to fetch link data for first time!</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="720" height="576" src="https://www.appcoda.com/content/images/wordpress/2020/07/t73_1_linkpresentation_demo.gif" alt="Using LinkPresentation Framework to Present Rich Links in iOS Apps" class="wp-image-18409"></figure>



<h2 class="wp-block-heading">Getting Started: Fetching Link Data</h2>



<p>By making clear what we&#x2019;re going to talk about in this post and what our course of actions is going to be, it&#x2019;s time to start building on the project and see the various aspects of the LinkPresentation framework.</p>



<p>Our starting point cannot be other than fetching the metadata for a link that is provided in the <em>InputLinkView</em> view. We&#x2019;ll be triggering the actual link data fetching when the Return key is tapped on the keyboard in order to be dismissed.</p>



<p>First, let&#x2019;s focus on the mechanism responsible for getting the link metadata. Open the <em>LinksModel.swift</em> file where we&#x2019;ll add the following <em>class</em> method in the <code>LinksModel</code> class:</p>



<pre class="wp-block-code"><code>class LinksModel {
    class func fetchMetadata(for link: String, completion: @escaping (Result&lt;LPLinkMetadata, Error&gt;) -&gt; Void) {

    }
}</code></pre>



<p>The first parameter value is the URL of the target link as a String value; the text given to the textfield in the <em>InputLinkView</em>.</p>



<p>Since fetching data from Internet is an asynchronous process, the second parameter is a <em>completion handler</em>, or in other words a <em>callback function</em> that will be called when the download is finished. The completion handler&#x2019;s argument is a <code>Result</code> type that will contain either the actual fetched data, or an error object in case the operation fails.</p>



<p><em>Note: Read more about the Result type <a href="https://developer.apple.com/documentation/swift/result?ref=appcoda.com">here</a>.</em></p>



<p>In case of success, the data of the Result type above is going to be a <code>LPLinkMetadata</code> object. <a href="https://developer.apple.com/documentation/linkpresentation/lplinkmetadata?ref=appcoda.com">LPLinkMetadata</a> class belongs to LinkPresentation framework, and it contains properties that describe a link:</p>



<ul><li>URL</li><li>Title</li><li>Icon</li><li>Image</li><li>Video</li></ul>



<p>We&#x2019;re going to use the returned <code>LPLinkMetadata</code> instance to show the rich link preview later, as well as to store fetched metadata locally.</p>



<p>Before we continue, add the following <code>import</code> statement right before the opening of the <code>LinksModel</code> class so we import the LinkPresentation framework and eliminate the error that is currently displayed in Xcode:</p>



<pre class="wp-block-code"><code>import LinkPresentation</code></pre>



<p>We&#x2019;ll begin implementing the above method by creating a URL object based on the provided URL string:</p>



<pre class="wp-block-code"><code>guard let url = URL(string: link) else { return }</code></pre>



<p>Now, we&#x2019;re going to meet another class of the LinkPresentation framework called <a href="https://developer.apple.com/documentation/linkpresentation/lpmetadataprovider?ref=appcoda.com">LPMetadataProvider</a>. This is the one that will perform the actual fetching of the link&#x2019;s metadata and it will return either a <code>LPLinkMetadata</code> object, or an error object if something turns out bad.</p>



<p>Using it is very simple. First we have to initialize an object of it:</p>



<pre class="wp-block-code"><code>let metadataProvider = LPMetadataProvider()</code></pre>



<p>Then, we need to call the method that will initiate the asynchronous fetching operation:</p>



<pre class="wp-block-code"><code>metadataProvider.startFetchingMetadata(for: url) { (metadata, error) in

}</code></pre>



<p>The completion handler of the method we just called contains two parameters: The link&#x2019;s metadata and an error object . We&#x2019;ll check if any of them is nil or not, and we&#x2019;ll pass the respective unwrapped value to the Result type that we&#x2019;ll feed to the completion handler of our method.</p>



<pre class="wp-block-code"><code>metadataProvider.startFetchingMetadata(for: url) { (metadata, error) in
    if let error = error {
        completion(.failure(error))
        return
    }

    if let metadata = metadata {
        completion(.success(metadata))
    }
}</code></pre>



<p>If <code>error</code> is not nil, then we pass the <code>.failure</code> case of the Result type as an argument to the completion handler with the error object as an associated value. Otherwise, we check if <code>metadata</code> is not nil and we pass the <code>.success</code> case of the Result type to the completion handler along with the unwrapped metadata object.</p>



<p>Here is the method we just implemented in one piece:</p>



<pre class="wp-block-code"><code>class func fetchMetadata(for link: String, completion: @escaping (Result&lt;LPLinkMetadata, Error&gt;) -&gt; Void) {
    guard let url = URL(string: link) else { return }

    let metadataProvider = LPMetadataProvider()
    metadataProvider.startFetchingMetadata(for: url) { (metadata, error) in
        if let error = error {
            completion(.failure(error))
            return
        }

        if let metadata = metadata {
            completion(.success(metadata))
        }
    }
}</code></pre>



<p>Let&#x2019;s open now the <em>InputLinkView.swift</em> file, where we&#x2019;ll make use of the above method. Go to the textfield&#x2019;s implementation into the view&#x2019;s body and spot the comment: <code>// Fetch link metadata.</code>.</p>



<p>The place where you find that comment is the action handler that gets called when the Return key in the keyboard is tapped while editing the textfield&#x2019;s text. Replace the comment with the following code:</p>



<pre class="wp-block-code"><code>LinksModel.fetchMetadata(for: self.link) { (result) in

}</code></pre>



<p>We&#x2019;re going to handle the above method&#x2019;s result right next. What really matters at this point is that the first important step has been now done! With just a few bits of code the demo application is capable of fetching the metadata for any given link!</p>



<h2 class="wp-block-heading">Handling Fetched Link Metadata</h2>



<p>We will handle the results of the <code>fetchMetadata(for:completion:)</code> in a new method that we&#x2019;ll implement here. But before that, go to the beginning of the <code>InputLinkView</code> structure and above the <code>body</code> implementation in order to add the following property which will hold the fetched metadata:</p>



<pre class="wp-block-code"><code>@State private var metadata: LPLinkMetadata?</code></pre>



<p>Additionally, import the LinkPresentation framework at the beginning of the file:</p>



<pre class="wp-block-code"><code>import LinkPresentation</code></pre>



<p>With the <code>metadata</code> property handy now, let&#x2019;s move on to the definition of a new method. Still inside the <code>InputLinkView</code> structure and right after the <code>body</code> implementation add the following:</p>



<pre class="wp-block-code"><code>private func handleLinkFetchResult(_ result: Result&lt;LPLinkMetadata, Error&gt;) {

}</code></pre>



<p>This method will accept the Result value coming from the completion handler of the <code>fetchMetadata(for:completion:)</code> and will handle both the metadata, if exists, and the error.</p>



<p>In case where link&#x2019;s metadata has been fetched successfully, then we&#x2019;ll get it from the associated value of the <code>success</code> case of the Result type and we&#x2019;ll assign it to the property we declared right before. In case of error, then we&#x2019;ll simply print it on the console; that&#x2019;s a fast solution good enough for this tutorial, however in real applications more appropriate actions should be taken, such as informing the user with an alert, or anything else suitable for the application.</p>



<p>All the above will take place in a <code>switch</code> statement, since it consists of the easiest way to extract associated values from a Result value. In addition to that, don&#x2019;t forget that metadata fetching is an asynchronous process and that our actions here will affect the user interface (UI), therefore it is mandatory everything to be done on the main thread.</p>



<p>Here&#x2019;s the full implementation of the <code>handleLinkFetchResult(_:)</code> method:</p>



<pre class="wp-block-code"><code>private func handleLinkFetchResult(_ result: Result&lt;LPLinkMetadata, Error&gt;) {
    DispatchQueue.main.async {
        switch result {
            case .success(let metadata): self.metadata = metadata
            case .failure(let error): print(error.localizedDescription)
        }
    }
}</code></pre>



<p>A couple of more tweaks in the original code of the starter project are necessary and we&#x2019;ll be good to go. First find the comment saying: <code>// Clear previous metadata.</code> in the view&#x2019;s body implementation.</p>



<p>The closure that this comment is written into is the textfield&#x2019;s handler that is being called when the textfield gets edited. For simplicity and in order to avoid small collateral complications that we don&#x2019;t need in this tutorial, we&#x2019;ll be scratching any metadata previously fetched whenever users edit the link&#x2019;s URL. So, replace that comment with:</p>



<pre class="wp-block-code"><code>if self.metadata != nil {
    self.metadata = nil
}</code></pre>



<p>After doing that, move a bit down in the existing code where you will find the <code>if false</code> condition right below a comment saying: <code>// Link preview.</code></p>



<p>This condition has no meaning and it works as a temporary placeholder for the actual condition that we&#x2019;ll specify right now. Replace <code>if false</code> with this:</p>



<pre class="wp-block-code"><code>if metadata != nil {
    ...
}</code></pre>



<p>If link&#x2019;s metadata exists and the <code>metadata</code> property we declared earlier is not nil, then we&#x2019;ll display the link preview (coming next). Otherwise, a placeholder text is displayed instead. We&#x2019;ll return at this specific point in a while and we&#x2019;ll replace the <code>EmptyView()</code> with an actual view that displays the link preview.</p>



<p>Finally, update the <code>fetchMetadata(for:completion:)</code> method call and in the completion closure call the <code>handleLinkFetchResult(_:)</code> method:</p>



<pre class="wp-block-code"><code>LinksModel.fetchMetadata(for: self.link) { (result) in
    self.handleLinkFetchResult(result)
}</code></pre>



<h2 class="wp-block-heading">The Link View</h2>



<p>One of the greatest things in LinkPresentation framework is that it provides a view that displays the link preview formatted properly, as long as it&#x2019;s fed with the link&#x2019;s metadata as a LPLinkMetadata object. On top of that, that view allows interaction when single tapping and long pressing on it; when the first happens it opens the selected link in the browser. In the second case, it shows a list of options including copying the link&#x2019;s URL, sharing, and more. However, that behaviour is not always desirable and you&#x2019;ll find out the reason later in this post.</p>



<p>The responsible class for creating rich link representations is called <a href="https://developer.apple.com/documentation/linkpresentation/lplinkview?ref=appcoda.com">LPLinkView</a>. Even though it offers important functionality out of the box, it has a downside when working in SwiftUI; it is a <em>UIView</em> view subclass (a UIKit view) and not a SwiftUI view! So, in order to use it we must mix UIKit and SwiftUI.</p>



<p>Thankfully, it&#x2019;s quite easy to wrap UIKit views in SwiftUI using the <em>UIViewRepresentable</em> protocol. The plan is to create a structure that conforms to <code>UIViewRepresentable</code> protocol, to implement a couple of required methods, and inside those methods to initialize and configure the UIView object.</p>



<p>To get started, open the <em>LinkView.swift</em> file, and right after the current import statement add the next two as well:</p>



<pre class="wp-block-code"><code>import UIKit
import LinkPresentation</code></pre>



<p>Now, let&#x2019;s create a new structure which will be used like any other SwiftUI view when we finish with it. We&#x2019;ll call it <em>LinkView</em>:</p>



<pre class="wp-block-code"><code>struct LinkView: UIViewRepresentable {

}</code></pre>



<p><code>UIViewRepresentable</code> protocol has a required associated type called <code>UIViewType</code> and it indicates the type of view that the structure will present. Here is how we fulfil that requirement in our case:</p>



<pre class="wp-block-code"><code>typealias UIViewType = LPLinkView</code></pre>



<p>After that, it&#x2019;s necessary to define the next two methods:</p>



<pre class="wp-block-code"><code>func makeUIView(context: Context) -&gt; LPLinkView {

}

func updateUIView(_ uiView: LPLinkView, context: Context) {

}</code></pre>



<p><code>makeUIView(context:)</code> must return an initialized view of the type specified in the <code>UIViewType</code> value. Here we are going to return a <code>LPLinkView</code> object.</p>



<p>The <code>updateUIView(_:context:)</code> method is not required to be mandatorily used, but it has to be defined. Use it when the view content must be updated when new information from SwiftUI exists, or the view cannot be fully configured in the <code>makeUIView(context:)</code> only.</p>



<p>A LPLinkView needs link metadata in order to display content. Therefore, add the next property in the <code>LinkView</code> structure; we&#x2019;ll provide metadata upon initialization of <code>LinkView</code> instances:</p>



<pre class="wp-block-code"><code>var metadata: LPLinkMetadata?</code></pre>



<p>Time to add content to <code>makeUIView(context:)</code> method. First, we&#x2019;ll make sure that the <code>metadata</code> property isn&#x2019;t nil. Then, we&#x2019;ll initialize a new <code>LPLinkView</code> view using the metadata, and we&#x2019;ll return it from the method:</p>



<pre class="wp-block-code"><code>func makeUIView(context: Context) -&gt; LPLinkView {
    guard let metadata = metadata else { return LPLinkView() }
    let linkView = LPLinkView(metadata: metadata)
    return linkView
}</code></pre>



<p>That&#x2019;s all we need! Here&#x2019;s the entire implementation of the <code>LinkView</code> structure:</p>



<pre class="wp-block-code"><code>struct LinkView: UIViewRepresentable {

    typealias UIViewType = LPLinkView

    var metadata: LPLinkMetadata?

    func makeUIView(context: Context) -&gt; LPLinkView {
        guard let metadata = metadata else { return LPLinkView() }
        let linkView = LPLinkView(metadata: metadata)
        return linkView
    }

    func updateUIView(_ uiView: LPLinkView, context: Context) {

    }
}</code></pre>



<p>The above makes it possible to use an UIView object in SwiftUI like any other view, and you&#x2019;re going to see that right next!</p>



<h2 class="wp-block-heading">Previewing Rich Links</h2>



<p>Back in the <em>InputLinkView.swift</em> file now where we&#x2019;ll make the first use of the <code>LinkView</code> structure we just implemented. Find the following condition:</p>



<pre class="wp-block-code"><code>if metadata != nil {
    EmptyView()
}</code></pre>



<p>We&#x2019;re going to replace the <code>EmptyView()</code> with a <code>LinkView</code> instance. Here it is:</p>



<pre class="wp-block-code"><code>if metadata != nil {
    LinkView(metadata: metadata)
        .aspectRatio(contentMode: .fit)
} else {
    ...
}</code></pre>



<p>Appending the <code>aspectRatio</code> modifier is done just for displaying properly the content of the link view, but it&#x2019;s not a requirement; we could have omitted it.</p>



<p>With the above condition now fixed it&#x2019;s possible to show a rich link preview when its metadata has been fetched, or a placeholder text when there&#x2019;s no metadata or the textfield is being edited.</p>



<p>We can run the app for first time at this point and try out what we&#x2019;ve managed so far! Click on the Plus button to add a link, type or paste any link in the textfield and tap on Return key (or hit Return on your keyboard if you&#x2019;re using Simulator). Wait for a few moments and the rich link will show up!</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="576" height="1024" src="https://www.appcoda.com/content/images/wordpress/2020/07/t73_2_fetch_link-576x1024.png" alt="Using LinkPresentation Framework to Present Rich Links in iOS Apps" class="wp-image-18410" srcset="https://www.appcoda.com/content/images/wordpress/2020/07/t73_2_fetch_link-576x1024.png 576w, https://www.appcoda.com/content/images/wordpress/2020/07/t73_2_fetch_link-169x300.png 169w, https://www.appcoda.com/content/images/wordpress/2020/07/t73_2_fetch_link-200x356.png 200w, https://www.appcoda.com/content/images/wordpress/2020/07/t73_2_fetch_link-680x1209.png 680w, https://www.appcoda.com/content/images/wordpress/2020/07/t73_2_fetch_link-400x711.png 400w, https://www.appcoda.com/content/images/wordpress/2020/07/t73_2_fetch_link-50x89.png 50w, https://www.appcoda.com/content/images/wordpress/2020/07/t73_2_fetch_link.png 750w" sizes="(max-width: 576px) 100vw, 576px"></figure>



<h2 class="wp-block-heading">The Custom Link Type</h2>



<p>If a link&#x2019;s metadata is not fetched for one-time use only, then the best practice that Apple recommends too is to save it locally (cache it) and load it when it&#x2019;s about to be needed again. That way users will have a better experience since they won&#x2019;t have to wait again and again until fetch is complete, and if they get connected through a cellular network they&#x2019;ll avoid having unnecessary costs in their mobile data plans for fetching link metadata that they have already fetched in the past.</p>



<p>The good news for us is that metadata represented by a <code>LPLinkMetadata</code> instance is serializable, which in plain words means that we can <em>archive</em> and <em>unarchive</em> using the <code>NSKeyedArchiver</code> and <code>NSKeyedUnarchiver</code> classes respectively.</p>



<p>However, we won&#x2019;t save the metadata alone straight to the disk in this post, and here is the reason:</p>



<p>Our next big goal is to display all stored links in a list, and in order to do that properly we need to have a type that conforms to <em>Identifiable</em> protocol and contains an <code>id</code> property.</p>



<p><code>LPLinkMetadata</code> class does not satisfy that requirement, so we are going to use a custom type that will contain an <code>id</code> property along with the metadata, and it will adopt the <code>Identifiable</code> protocol so it can be used in SwiftUI lists.</p>



<p>That custom type has been defined already and it&#x2019;s the <code>Link</code> class in the <code>Link.swift</code> file. Open it and add the following two properties:</p>



<pre class="wp-block-code"><code>var id: Int?
var metadata: LPLinkMetadata?</code></pre>



<p>Since we&#x2019;re making use of the LinkPresentation API, we need to import that framework in this file too:</p>



<pre class="wp-block-code"><code>import LinkPresentation</code></pre>



<p>Additionally, adopt the <code>Identifiable</code> protocol to make it possible to list <code>Link</code> items later:</p>



<pre class="wp-block-code"><code>class Link: Identifiable { ... }</code></pre>



<p>Now, as I said already before, we won&#x2019;t archive and save the <code>metadata</code> only. Instead, we&#x2019;ll archive and save the entire instance of a <code>Link</code> object so it includes both the <code>id</code> and the <code>metadata</code>. But in order to do that it&#x2019;s necessary to make <code>Link</code> class:</p>



<ul><li>A subclass of the <code>NSObject</code> class.</li><li>Conform to the <code>NSSecureCoding</code> protocol (which in turn adopts <code>NSCoding</code>). This will enable us to serialize and deserialize instances of <code>Link</code> (and eventually save to disk) and take advantage of the fact that <code>LPLinkMetadata</code> is serializable.</li></ul>



<p><em>Note: We&#x2019;ll make <code>Link</code> class conform to <code>NSSecureCoding</code> instead of <code>NSCoding</code> because <code>metadata</code>, a <code>LPLinkMetadata</code> object, is serializable with the <code>NSSecureCoding</code> protocol. Read more about <a href="https://developer.apple.com/documentation/foundation/nscoding?ref=appcoda.com">NSCoding</a> and <a href="https://developer.apple.com/documentation/foundation/nssecurecoding?ref=appcoda.com">NSSecureCoding</a>, or make a search on the web for additional information about them.</em></p>



<p>So, we&#x2019;ll continue by updating the class header line as shown:</p>



<pre class="wp-block-code"><code>class Link: NSObject, NSSecureCoding, Identifiable { ... }</code></pre>



<p><code>NSSecureCoding</code> protocol brings along new requirements: We must include a required associated value to support secure coding, and to implement two methods; one for encoding stored properties and one to initialize instances of <code>self</code> from archived objects:</p>



<pre class="wp-block-code"><code>static var supportsSecureCoding = true

func encode(with coder: NSCoder) {

}

required init?(coder: NSCoder) {

}</code></pre>



<p>Both of the above methods must be implemented by any custom type that needs to become capable of being serialized and deserialized.</p>



<p>Starting with the <code>encode(with:)</code> method, here&#x2019;s how we&#x2019;re encoding the two properties of the <code>Link</code> class so they become serializable:</p>



<pre class="wp-block-code"><code>func encode(with coder: NSCoder) {
    guard let id = id, let metadata = metadata else { return }
    coder.encode(NSNumber(integerLiteral: id), forKey: &quot;id&quot;)
    coder.encode(metadata as NSObject, forKey: &quot;metadata&quot;)
}</code></pre>



<p>You might find peculiar that we&#x2019;re encoding properties as Objective-C objects (NSNumber, NSObject) instead of encoding as Swift Int value and Any object respectively. Actually, that&#x2019;s because of a requirement that results from the way <em>decoding</em> must be done when adopting <code>NSSecureCoding</code> protocol.</p>



<p>To be more precise, you will see next that in order to decode in the <code>init(coder:)</code> we&#x2019;re making use of the <code>decodeObject(of:forKey:)</code> method as Apple recommends. The first argument must be a subclass of the <code>NSObject</code> class, and that creates the need to encode accordingly. Also, given what I just said and after you&#x2019;ll see the implementation of the <code>init(coder:)</code> method right next you can understand why we made <code>Link</code> class a <code>NSObject</code> subclass. I leave it up to you to read more information about <code>NSSecureCoding</code>.</p>



<p>Going to the <code>init(coder:)</code> initializer now, here we have to decode previously encoded values and objects and assign them to the proper properties.</p>



<pre class="wp-block-code"><code>required init?(coder: NSCoder) {
    id = coder.decodeObject(of: NSNumber.self, forKey: &quot;id&quot;)?.intValue
    metadata = coder.decodeObject(of: LPLinkMetadata.self, forKey: &quot;metadata&quot;)
}</code></pre>



<p>Before we move on to the next step, add the next default initializer to <code>Link</code> class that will allow us to create new objects:</p>



<pre class="wp-block-code"><code>override init() {
    super.init()
}</code></pre>



<p>The implementation of the <code>Link</code> class is complete. You&#x2019;ll see why the above are necessary in the following parts.</p>



<h2 class="wp-block-heading">Saving Link Data</h2>



<p>Switch to the <em>LinksModel.swift</em> file now where the actual saving of <code>Link</code> objects is going to take place. However, before we get to that, let&#x2019;s start by creating a method in the <code>LinksModel</code> class that will create new <code>Link</code> objects using metadata that is provided as an argument:</p>



<pre class="wp-block-code"><code>func createLink(with metadata: LPLinkMetadata) {
    let link = Link()
    link.id = Int(Date.timeIntervalSinceReferenceDate)
    link.metadata = metadata
    links.append(link)
    saveLinks()
}</code></pre>



<p>Here&#x2019;s what is going on in the above method:</p>



<ul><li>First a new <code>Link</code> object is being created.</li><li>As a quick solution for the value of <code>id</code> property we&#x2019;re getting the current timestamp and we keep only its integer part. We assign it to the <code>id</code> property as the identifier of the <code>link</code> object.</li><li>We assign the <code>metadata</code> parameter value to the respective property of the <code>link</code> object.</li><li>We append the newly created object to the <code>links</code> collection (already defined in the <code>LinksModel</code> class).</li><li>Finally we call the <code>saveLinks()</code> method that we&#x2019;re going to implement as the next step in the whole process we&#x2019;re doing here.</li></ul>



<p>So, time to work on the actual saving of the link data to the disk. Using the <code>NSKeyedArchiver</code> class we&#x2019;ll serialize the entire <code>links</code> array, but note that this is possible because its items are serializable (we took care of that in the previous part). Doing so isn&#x2019;t difficult at all, and it&#x2019;s recommended to be done in a <code>do-catch</code> statement since an exception might be thrown. Here it is:</p>



<pre class="wp-block-code"><code>fileprivate func saveLinks() {        
    do {
        let data = try NSKeyedArchiver.archivedData(withRootObject: links, requiringSecureCoding: true)
        guard let docDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        try data.write(to: docDirURL.appendingPathComponent(&quot;links&quot;))
    } catch {
        print(error.localizedDescription)
    }
}</code></pre>



<p><em>Note: To be able to find and see the created file in Finder just add the next line as the last one in the <code>do</code> statement above:</em></p>



<pre class="wp-block-code"><code>print(docDirURL.appendingPathComponent(&quot;links&quot;))</code></pre>



<p>When the <code>NSKeyedArchiver.archivedData(withRootObject: links, requiringSecureCoding: true)</code> code is executed, the <code>encode(with:)</code> encoder method we met before gets called for every <code>Link</code> object in the <code>links</code> array so each one of them to be serialized. The resulting archived object is assigned to the <code>data</code> object as shown above. It&#x2019;s important to stress here that the above wouldn&#x2019;t work if we hadn&#x2019;t made <code>Link</code> class serializable by conforming to <code>NSSecureCoding</code> protocol!</p>



<p><em>Note #2: Read more about NSKeyedArchiver and NSKeyedUnarchiver <a href="https://developer.apple.com/documentation/foundation/nskeyedarchiver?ref=appcoda.com">here</a> and <a href="https://developer.apple.com/documentation/foundation/nskeyedunarchiver?ref=appcoda.com">here</a> respectively.</em></p>



<p>In case you wanted to serialize the metadata only and avoid all the hassle we went through in the <code>Link</code> class, then you should provide a <code>LPLinkMetadata</code> object as the first argument above instead of <code>links</code>, and probably to choose a specific name for the file that will contain the serialized metadata. Here&#x2019;s an example method that does that:</p>



<pre class="wp-block-code"><code>func save(metadata: LPLinkMetadata) {        
    do {
        let data = try NSKeyedArchiver.archivedData(withRootObject: metadata, requiringSecureCoding: true)
        guard let docDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
        try data.write(to: docDirURL.appendingPathComponent(&quot;SOME_BETTER_FILE_NAME&quot;))
    } catch {
        print(error.localizedDescription)
    }
}</code></pre>



<p>And by having said that, there&#x2019;s one last action remaining to be done in order to save fetched link metadata to disk. We must call the <code>createLink(with:)</code> method from the <code>InputLinkView</code> structure.</p>



<p>Open the <em>InputLinkView.swift</em> file and find the comment saying:</p>



<p><code>// Save link metadata.</code></p>



<p>This closure gets called when the top-right button with the checkmark is tapped in the app. The goal is to save the link metadata and dismiss the modal view.</p>



<p>With that in mind, replace the above comment with the next simple call:</p>



<pre class="wp-block-code"><code>self.keepLink()</code></pre>



<p>And now let&#x2019;s implement that <code>keepLink()</code> method which is fairly simple right after the <code>body</code> implementation and inside the <code>InputLinkView</code> structure:</p>



<pre class="wp-block-code"><code>private func keepLink() {
    guard let metadata = self.metadata else { return }

    // Create the Link object and save all links metadata to file.
    self.linksList.createLink(with: metadata)

    // Dismiss InputLinkView instance.
    self.presentationMode.wrappedValue.dismiss()
}</code></pre>



<p>Run the app again now and after having fetched a link&#x2019;s metadata tap on the top-right button. Link should be saved and the view to be dismissed.</p>



<h2 class="wp-block-heading">Loading Link Data</h2>



<p>Back to <em>LinksModel.swift</em> file and in the <code>LinksModel</code> class, where we&#x2019;ll add a new method responsible for loading and deserializing previously serialized and stored <code>Link</code> objects. In this method we&#x2019;ll follow the opposite path from the one we followed earlier; first we&#x2019;ll load the file contents to a Data object (if the file exists), and then we&#x2019;ll use the <code>NSKeyedUnarchiver</code> class to unarchive links data.</p>



<p>Here it is:</p>



<pre class="wp-block-code"><code>fileprivate func loadLinks() {
    guard let docDirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
    let linksURL = docDirURL.appendingPathComponent(&quot;links&quot;)

    if FileManager.default.fileExists(atPath: linksURL.path) {
        do {
            let data = try Data(contentsOf: linksURL)
            guard let unarchived = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? [Link] else { return }
            links = unarchived            
        } catch {
            print(error.localizedDescription)
        }
    }
}</code></pre>



<p>See that <code>links</code> property gets a value if only code execution mades it successfully up to that point. This means that the file must exist, a Data object to be properly initialized using the the file contents, and that data to be unarchived without problems.</p>



<p>We want links to be loaded when the app starts running so we can display them. For that reason, the above method must be called when <code>LinksModel</code> class is initialized. Add the following <code>init()</code> method that will be called upon <code>LinksModel</code> initialization:</p>



<pre class="wp-block-code"><code>init() {
    loadLinks()
}</code></pre>



<p>We&#x2019;re now in the position where we can update the UI and display a list of links.</p>



<h2 class="wp-block-heading">Listing Cached Links</h2>



<p>Open the <em>LinksListView.swift</em> file now, where <code>LinksListView</code> is the place where we&#x2019;ll list loaded links. At the beginning of the <code>body</code> implementation you&#x2019;ll find a Text and an empty view inside a vertical stack. We&#x2019;ll deal with the empty view later, but now we&#x2019;ll replace the Text control with a List.</p>



<p>To do so, make sure you select and delete this:</p>



<pre class="wp-block-code"><code>Text(&quot;Links will appear here&quot;)</code></pre>



<p>Next, add the following List in place of Text:</p>



<pre class="wp-block-code"><code>List(linksList.links, rowContent: { link in

})</code></pre>



<p>Listing <code>Link</code> objects the way shown above is the reason why we adopted the <code>Identifiable</code> protocol in the <code>Link</code> class and we added the <code>id</code> property. Inside the List closure now we&#x2019;ll create a button, so each item to be tappable:</p>



<pre class="wp-block-code"><code>Button(action: {

}) {

}
    .padding(.vertical, 20)</code></pre>



<p>The first closure in the Button is being called every time the button is tapped. Let&#x2019;s leave it empty for now, and let&#x2019;s focus on the second closure that regards what the button is going to display as a content.</p>



<p>That content is nothing else but a <code>LinkView</code> that will be using the metadata of each link object in the list:</p>



<pre class="wp-block-code"><code>LinkView(metadata: link.metadata)</code></pre>



<p>Putting everything together, here&#x2019;s the list along with the button:</p>



<pre class="wp-block-code"><code>List(linksList.links, rowContent: { link in
    Button(action: {

    }) {
        LinkView(metadata: link.metadata)
    }
        .padding(.vertical, 20)
})</code></pre>



<p>Run the app now to see rich links being listed. If you have saved already some links they&#x2019;ll appear as soon as you launch the app. In any case, add a few more links in the <code>InputLinkView</code> and come back to see them being added to the links list.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="720" height="576" src="https://www.appcoda.com/content/images/wordpress/2020/07/t73_3_listed_links.gif" alt="Using LinkPresentation Framework to Present Rich Links in iOS Apps" class="wp-image-18411"></figure>



<h2 class="wp-block-heading">Sharing Links With The Activity Controller</h2>



<p>If you&#x2019;ve played a bit with the rich link previews either in the <code>InputLinkView</code> or in the <code>LinksListView</code> then you&#x2019;ve found out already that by single tapping on a link causes it to open in the browser. If you long press a link, then a preview of the target website along with various options for opening, copying, or sharing the link also appear.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="720" height="576" src="https://www.appcoda.com/content/images/wordpress/2020/07/t73_4_single_long_tap.gif" alt="Using LinkPresentation Framework to Present Rich Links in iOS Apps" class="wp-image-18412"></figure>



<p>Let&#x2019;s focus on the sharing feature that shows up after performing a long tap to the link preview. An activity view controller appears with various sharing options available to the device, and we get a nice functionality for free, but there&#x2019;s a disadvantage. The displayed link details are being fetched again and again from the target URL whenever the activity controller is being presented.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="720" height="576" src="https://www.appcoda.com/content/images/wordpress/2020/07/t73_5_activity_fetch_data.gif" alt="Using LinkPresentation Framework to Present Rich Links in iOS Apps" class="wp-image-18413"></figure>



<p>Obviously that&#x2019;s not a desirable thing to happen, especially when we&#x2019;ve already fetched and cached link metadata. So the question that arises here is: Can we use the metadata that we have already fetched in order to provide them to the activity view controller and to avoid fetching repeatedly the same data?</p>



<p>The answer is yes, and actually Apple recommends to do so! However we can&#x2019;t do that in the activity view controller presented from the default link view. We must initialize and present our own activity view controller, and in that case it&#x2019;s possible to feed it with any data we want to.</p>



<p>That sounds great, but the fact that we&#x2019;re working in SwiftUI makes things a bit more complicated for us! Activity view controller is a UIKit view controller, so we must &#x201C;port&#x201D; it in SwiftUI. Don&#x2019;t worry though! It&#x2019;s a quite straightforward process pretty similar to the way we imported LPLinkView previously using the <code>UIViewRepresentable</code> protocol.</p>



<p>What we&#x2019;re going to do here is a two-step process: First, we&#x2019;ll create a UIKit view controller that will initialize a new activity view controller and it will adopt the <code>UIActivityItemSource</code> protocol. That will allow to implement specific methods through which we&#x2019;ll provide link metadata to the activity controller.</p>



<p>Then, we&#x2019;ll create a new custom structure which we&#x2019;ll call <code>ShareLinkView</code>. It will conform to <code>UIViewControllerRepresentable</code> protocol; this will make it possible to &#x201C;port&#x201D; the UIKit view controller to SwiftUI and use it like any other native <code>View</code> object.</p>



<h3 class="wp-block-heading">The ActivityController View Controller</h3>



<p>With all the above said, let&#x2019;s keep building on our app. Open the <em>ShareLinkView.swift</em> file, and start by importing the following two frameworks:</p>



<pre class="wp-block-code"><code>import UIKit
import LinkPresentation</code></pre>



<p>Next, define the following class:</p>



<pre class="wp-block-code"><code>class ActivityController: UIViewController, UIActivityItemSource {

}</code></pre>



<p>We create the <code>ActivityController</code> type, which is a view controller and adopts the <code>UIActivityItemSource</code> protocol. That protocol has a couple of required methods that need to be implemented, plus one more that we&#x2019;ll add specifically for returning link metadata. Before we get there however, it&#x2019;s necessary to make some other preparations.</p>



<p>So, at first declare the following properties in the <code>ActivityController</code> class:</p>



<pre class="wp-block-code"><code>var metadata: LPLinkMetadata?
var activityViewController: UIActivityViewController?
var completion: UIActivityViewController.CompletionWithItemsHandler?</code></pre>



<ul><li><code>metadata</code> is the link&#x2019;s metadata that will be displayed on the activity controller as a <code>LPLinkMetadata</code> object.</li><li><code>activityViewController</code> is the actual activity view controller that will be presented.</li><li><code>completion</code> is a completion handler that will be called by the activity view controller when it gets dismissed.</li></ul>



<p>Next, override the <code>viewDidAppear(_:)</code> that will be called when our view controller has appeared. In it, we&#x2019;ll initialize the activity controller:</p>



<pre class="wp-block-code"><code>override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    activityViewController = UIActivityViewController(activityItems: [self], applicationActivities: nil)
    activityViewController?.completionWithItemsHandler = completion
    present(activityViewController!, animated: true, completion: nil)
}</code></pre>



<p>Two important things to notice here:</p>



<ol><li>An array of <code>self</code> items is given as the activity items at the controller&#x2019;s initialization. This is possible because of the <code>UIActivityItemSource</code> protocol and the methods we&#x2019;ll implement next.</li><li>The <code>completion</code> property is assigned to the <code>completionWithItemsHandler</code> property of the activity view controller. When it&#x2019;ll be dismissed, that completion handler will be called and let the <code>ShareLinkView</code> that we&#x2019;ll implement next know about that event.</li></ol>



<p>Finally, time for the <code>UIActivityItemSource</code> methods. The two of them that are required are these:</p>



<pre class="wp-block-code"><code>func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -&gt; Any {
    return &quot;&quot;
}

func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -&gt; Any? {
    return metadata?.originalURL
}</code></pre>



<p>In the first method we can return anything we want as placeholder item before an actual item becomes available. It doesn&#x2019;t really matter here because the link metadata that we&#x2019;ll provide will appear instantly, so simply returning an empty string value is enough.</p>



<p>The second method returns the actual data that the activity controller should act upon. Since we&#x2019;re talking about links, this is the original URL of the link that will be used by any activity chosen in the activity controller.</p>



<p>Lastly, there&#x2019;s one more method specific for the LinkPresentation framework; it feeds the activity controller with the link metadata object:</p>



<pre class="wp-block-code"><code>func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -&gt; LPLinkMetadata? {
    return metadata
}</code></pre>



<p>The <code>ActivityController</code> class is ready, so let&#x2019;s go straight ahead to use it.</p>



<h3 class="wp-block-heading">The ShareLinkView</h3>



<p>Previously in this post we created the <code>LinkView</code> structure, a custom type that was adopting the <code>UIViewRepresentable</code> protocol in order to make it possible to use a UIView object in SwiftUI.</p>



<p>In a quite similar fashion we&#x2019;re going to create a new custom type to use in SwiftUI called <code>ShareLinkView</code>, but this time instead of adopting the <code>UIViewRepresentable</code> protocol, it will adopt the <code>UIViewControllerRepresentable</code> since it&#x2019;s a view controller what we need to present.</p>



<p>Right after the closing of the <code>ActivityController</code> class add this:</p>



<pre class="wp-block-code"><code>struct ShareLinkView: UIViewControllerRepresentable {

}</code></pre>



<p>Once again, it&#x2019;s necessary to specify the view controller type that we&#x2019;ll return to an associated value of the <code>UIViewControllerRepresentable</code> protocol, and implement two methods; one that will return the actual view controller and one that gets called in order to update the view controller when there are changes in SwiftUI environment.</p>



<pre class="wp-block-code"><code>typealias UIViewControllerType = ActivityController

func makeUIViewController(context: Context) -&gt; ActivityController { }

func updateUIViewController(_ uiViewController: ActivityController, context: Context) { }</code></pre>



<p>See that the above match to what we already met in the <code>LinkView</code>:</p>



<pre class="wp-block-code"><code>typealias UIViewType = LPLinkView

func makeUIView(context: Context) -&gt; LPLinkView { }

func updateUIView(_ uiView: LPLinkView, context: Context) { }</code></pre>



<p>Besides the above, we need to declare the following two properties in the <code>ShareLinkView</code> struct:</p>



<pre class="wp-block-code"><code>var metadata: LPLinkMetadata?
var completion: (() -&gt; Void)</code></pre>



<p><code>metadata</code> is the metadata object that will be passed to the activity view controller. <code>completion</code> is another completion handler that will notify SwiftUI that the activity view controller has been dismissed.</p>



<p>In the <code>makeUIViewController(context:)</code> method we&#x2019;ll create a new <code>ActivityController</code> instance and we&#x2019;ll pass the metadata object:</p>



<pre class="wp-block-code"><code>func makeUIViewController(context: Context) -&gt; ActivityController {
    let activityController = ActivityController()
    activityController.metadata = metadata
}</code></pre>



<p>Then, we&#x2019;ll deal with the completion handler of the activity controller; we&#x2019;ll just call the <code>completion</code> property of the <code>ShareLinkView</code> structure to communicate to SwiftUI that the controller has been dismissed:</p>



<pre class="wp-block-code"><code>func makeUIViewController(context: Context) -&gt; ActivityController {
    ...

    activityController.completion = { (activityType, completed, returnedItems, error) in
        self.completion()
    }
}</code></pre>



<p>The completion&#x2019;s arguments shown above are there just for demonstration; we&#x2019;re not using them here. See Quick Help in Xcode for details what each parameter value is for.</p>



<p>Since the <code>activityController</code> instance we&#x2019;re creating here is not loaded from any XIB or storyboard file, it&#x2019;s necessary to call the <code>loadView()</code> method of the <code>UIViewController</code> class; this will trigger the user interface to be presented and the <code>viewDidAppear(_:)</code> we implemented earlier to be called in order to create the activity view controller:</p>



<pre class="wp-block-code"><code>func makeUIViewController(context: Context) -&gt; ActivityController {
    ...

    activityController.loadView()
}</code></pre>



<p>Finally, we must return the <code>activityController</code> instance:</p>



<pre class="wp-block-code"><code>func makeUIViewController(context: Context) -&gt; ActivityController {
    ...

    return activityController
}</code></pre>



<p>Regarding the <code>updateUIViewController(_:context:)</code> method, we&#x2019;ll leave it empty; there&#x2019;s nothing we really need to do with it.</p>



<p>Here&#x2019;s the <code>ShareLinkView</code> structure complete:</p>



<pre class="wp-block-code"><code>struct ShareLinkView: UIViewControllerRepresentable {
    typealias UIViewControllerType = ActivityController

    var metadata: LPLinkMetadata?
    var completion: (() -&gt; Void)

    func makeUIViewController(context: Context) -&gt; ActivityController {
        let activityController = ActivityController()
        activityController.metadata = metadata
        activityController.completion = { (activityType, completed, returnedItems, error) in
            self.completion()
        }
        activityController.loadView()
        return activityController
    }

    func updateUIViewController(_ uiViewController: ActivityController, context: Context) {

    }
}</code></pre>



<h3 class="wp-block-heading">Using The ShareLinkView</h3>



<p>Now that all the preparation has been done, we can go ahead and present the activity view controller passing the existing metadata of a link. Open the <em>LinksListView.swift</em> file, and declare the following property in the <code>LinksListView</code> structure that will keep the <code>Link</code> object matching to any selected link:</p>



<pre class="wp-block-code"><code>@State private var linkToShare: Link?</code></pre>



<p>Now, in the action handler closure of the button inside the list control, add the following:</p>



<pre class="wp-block-code"><code>Button(action: {
    // Add this...
    self.linkToShare = link
}) {
    ...
}</code></pre>



<p>It&#x2019;s finally time to show the <code>ShareLinkView</code> which will actually present the <code>ActivityController</code> which in turn will present the activity view controller.</p>



<p>We&#x2019;ll be presenting a new instance of the <code>ShareLinkView</code> every time there&#x2019;s a link to share, or in other words the <code>linkToShare</code> property is not nil. Inside the <code>body</code> implementation of the <code>LinksListView</code>, find the <code>EmptyView()</code> declaration right after the list and delete it. Add this instead:</p>



<pre class="wp-block-code"><code>if linkToShare != nil {
    ShareLinkView(metadata: linkToShare!.metadata, completion: {
        self.linkToShare = nil
    })
        .frame(width: 0, height: 0)
}</code></pre>



<p>By tapping on any item in the list the state of the <code>linkToShare</code> is changed and SwiftUI updates the UI because of that. While initializing a new instance of the <code>ShareLinkView</code> we pass the metadata of the selected <code>Link</code> object, and in the completion handler&#x2019;s closure we make <code>linkToShare</code> nil again; this will force SwiftUI to hide the <code>ShareLinkView</code> view.</p>



<p>Also notice that we specify a zero frame using the <code>frame</code> modifier. This is done in order to avoid displaying the empty view of our custom <code>ActivityController</code> view controller; we just need the activity view controller to appear. Feel free to comment it out and see the effect of that modifier.</p>



<p>Run the app now and tap on any item in the list, but <em>not</em> on a link view itself. You&#x2019;ll see that the activity view controller is presented properly and there is no waiting time until link metadata to be displayed on it.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="720" height="576" src="https://www.appcoda.com/content/images/wordpress/2020/07/t73_6_show_custom_activity_controller.gif" alt="Using LinkPresentation Framework to Present Rich Links in iOS Apps" class="wp-image-18414"></figure>



<p>If you tap or long press on the link view, you&#x2019;ll see that the previous default behaviour is still there. There will be times where that behaviour will be meaningful and useful, and times where we won&#x2019;t actually need it. This is one of them; we want to present the activity view controller when tapping on a list item and avoid the confusion when tapping on a link view.</p>



<p>So, let&#x2019;s disable it, and in order to do that add the following modifier right after the initialization of the <code>LinkView</code> object:</p>



<pre class="wp-block-code"><code>LinkView(metadata: link.metadata)
    .disabled(true)</code></pre>



<p>Note that it&#x2019;s relatively easy to implement the rest of the missing functionalities in case you need to disable link view&#x2019;s interaction in your apps, such as copying or opening the URL of the link.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>In my opinion, LinkPresentation framework is something that was missing for years from the iOS and macOS SDK. It makes it super easy and fast to present rich links inside apps and actually in a way that&#x2019;s quite familiar to users. </p>



<p>If you&#x2019;re working with UIKit (or AppKit on macOS), it might be a bit more straightforward to deal with what LinkPresentation framework provides. However, as you&#x2019;ve seen in this tutorial, it&#x2019;s not difficult at all to use it with SwiftUI as well, and on top of that we implemented solutions that bring UIKit parts to SwiftUI environment. Just see how we implemented the <code>LinkView</code> and <code>ShareLinkView</code> structures. </p>



<p>In overall, working with LinkPresentation framework does not hide any hard task, and on the contrary, it&#x2019;s a pleasure implementing around it. I hope you found this post useful. Thanks for reading!</p>



<p>For the full demo project, please <a href="https://github.com/appcoda/LinkPresentationDemo?ref=appcoda.com" class="rank-math-link">download it on GitHub</a>.</p>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[Best Practice: How to Fetch Remote Images in Swift Projects]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>One of the most common tasks that iOS -and not only- developers are called to perform in their programming endeavours is <em>fetching and managing remote images</em> that should be displayed to an app. For instance, suppose that you&#x2019;re building the next great messaging application where obviously users have</p>]]></description><link>https://www.appcoda.com/fetch-remote-images-swift/</link><guid isPermaLink="false">66612a0f166d3c03cf0114cc</guid><category><![CDATA[iOS Programming]]></category><category><![CDATA[SwiftUI]]></category><dc:creator><![CDATA[Gabriel Theodoropoulos]]></dc:creator><pubDate>Fri, 05 Jun 2020 17:12:22 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2020/06/hytvmlxkvoa.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2020/06/hytvmlxkvoa.jpg" alt="Best Practice: How to Fetch Remote Images in Swift Projects"><p>One of the most common tasks that iOS -and not only- developers are called to perform in their programming endeavours is <em>fetching and managing remote images</em> that should be displayed to an app. For instance, suppose that you&#x2019;re building the next great messaging application where obviously users have contacts. Those contacts have avatar images residing to a server. When users connect to the app then avatars must be downloaded in order to be used by the app. Or, another example, think of an app that manages the event of a worldwide convention, and among its features is the list of all attendees. Their images must be fetched and handled by the app, and displayed properly when necessary.</p>



<p>What makes things complicated is the fact that image fetching is an <em>asynchronous</em> process. When fetching multiple images then it&#x2019;s really easy to display the wrong image to the wrong place in certain cases. Think of the contact list again, which is a list of images with text at its simplest form. Displaying fetched avatar images to the proper contacts can end up being a hell depending on how image handling has been implemented. It would be really bad to see the app displaying the wrong avatar next to each name, and it would be even worse to have avatar images being replaced by other avatar images when contacts appear and disappear while scrolling. Have you seen this maybe? A perfect chaos and no consistency at all!</p>



<p>Another troubling point can be the way images are handled locally once they are fetched. Are there any rules about naming or storing details? Are there best and worst practices one should follow? Should images be stored in <em>documents</em> or in <em>caches</em> directory? These and more questions will most probably arise when building an app and it&#x2019;s about time to deal with remote images. The answers though should not be given and implemented when an actual application is being built; that kind of issues should be already fixed and be part of the solution, not the problem.</p>



<p>So, here we come. In this tutorial I will present you a simple, yet quite effective recipe that makes fetching remote images and then handling them locally a really straightforward task. I&#x2019;ll show you how to create a handy tool that you&#x2019;ll be able to use right when it&#x2019;s needed, and you won&#x2019;t need to worry anymore about all that I described above. Even if you won&#x2019;t use what we&#x2019;ll build here eventually, you might get some ideas to apply in your own solutions. So, keep on reading to find out some really interesting stuff.</p>



<h2 class="wp-block-heading">What We&#x2019;re Going To Build</h2>



<p>The main &#x201C;component&#x201D; we&#x2019;re going to implement in this post is a <strong>protocol</strong> along with a <em>default implementation</em> that will make possible to fetch an image from a remote source, or load it from a local file. Creating a <a href="https://www.appcoda.com/pop-vs-oop/">protocol</a> makes it super-easy to integrate image handling capabilities on any custom type simply by adopting it, so in plain words our soon-to-be-implemented solution can be used out of the box everywhere. However, what&#x2019;s the point to get into that trouble if we&#x2019;re just to create a method that will fetch a single image?</p>



<p>The truth is that we won&#x2019;t stop there; we&#x2019;ll add more capabilities and we&#x2019;ll support <em>multiple image fetching</em>, as well as <em>single and batch image deletion</em>. As a bonus point, we&#x2019;ll add the capability to <em>save</em> a new image locally straight from an app, even though it doesn&#x2019;t sound like a much related thing to do. It would be a shame though to have a component that fetches, loads and deletes images, but it does not support saving new ones and just for that operation to need a different tool or implementation.</p>



<p>Except for the protocol that will be the primary and most important custom type, there will be two additional custom types, two <strong>structures</strong>:</p>



<ol><li>The first one will be used to specify optionally some settings. It&#x2019;s necessary so the solution we&#x2019;ll build to be as much flexible as possible, and you&#x2019;ll understand pretty soon what I mean by that.</li><li>The second structure will be working behind the scenes and it will contain a small collection of <em>static</em> methods and properties valuable for the default implementation of the protocol&#x2019;s methods.</li></ol>



<p>We&#x2019;ll build everything step by step and by discussing each aspect thoroughly. In order to see the results of our efforts though we&#x2019;ll use&#x2026;</p>



<h2 class="wp-block-heading">A Demo Project for Fetching Remote Images</h2>



<p>Before we start doing anything, it&#x2019;s necessary to download a <a href="https://github.com/appcoda/FetchableImage/raw/master/starter.zip?ref=appcoda.com">starter project</a>. It contains a <em><a href="https://www.appcoda.com/swiftui">SwiftUI</a> based iOS app</em> called <em>FetchableImageDemo</em>. Let me describe fast its various parts starting from the views:</p>



<ul><li><code>UserView</code>: A custom view with an Image and a Text that will display an avatar image and the contact name. It&#x2019;s embedded to two other views, <code>RandomContactView</code> and <code>ContactDetailsView</code>.</li><li><code>RandomContactView</code>: A view that besides the <code>UserView</code>, also contains a button that triggers the selection of a contact randomly. We&#x2019;ll use it for testing single image fetching.</li><li><code>ContactListView</code>: The primary component here is a List that will be displaying a list of contacts. We&#x2019;ll use it for testing multiple image fetching and deletion. This view is embedded in a navigation view with two bar items; one for initiating the fetching process, and one for deleting all fetched avatars. When tapping on any contact item, the <code>ContactDetailsView</code> will be shown. Additionally, it contains another custom view, the <code>ProgressView</code>, which will display visually the download progress of all avatars.</li><li><code>ContactDetailsView</code>: Another view that embeds the <code>UserView</code>, and it also contains a button that will enable us to try out deleting a single image (the selected contact&#x2019;s avatar), as well as to fetch it back.</li><li><code>ProgressView</code>: A custom implementation of a progress bar.</li><li><code>Tabs</code>: <code>FetchableImageDemo</code> is a tab bar application, and <code>Tabs</code> view is the one creating the tabs.</li></ul>



<p>Besides the above, you&#x2019;ll also find:</p>



<ul><li>The <code>Contact</code> structure: It represents a single contact. It contains an <code>id</code>, <code>name</code>, <code>avatarURL</code>, and <code>avatar</code>. We&#x2019;ll be using the <code>avatarURL</code> in order to fetch the image that we&#x2019;ll be assigning to <code>avatar</code>. It conforms to <code>Decodable</code> protocol so fake contact data can be loaded and decoded from the two JSON files included in the project, and also conforms to <code>Identifiable</code> protocol in order to easily iterate through such objects in the <code>ContactListView</code> using a <code>ForEach</code> loop.</li><li>The <code>RandomContactModel</code> class: We&#x2019;ll use it as the model for the <code>RandomContactView</code>. It&#x2019;s partially implemented, and when we&#x2019;ll finish with it it&#x2019;ll be able to pick a random contact and fetch its avatar image using the protocol that we&#x2019;ll build next.</li><li>The <code>ContactListModel</code> class: The model for the <code>ContactListView</code> class. We&#x2019;ll use it to try out most of the features we&#x2019;ll add to the protocol, such as multiple image fetching and deletion, as well as single image deletion and download progress.</li></ul>



<p>The fake contact data we&#x2019;ll use is already embedded to the project. There are two JSON files named <em>fakedata_small.json</em> and <em>fakedata.json</em>, where the first one has data for 10 contacts, and the second data for 50 contacts. We&#x2019;ll use the first one with the <code>RandomContactModel</code> and the <code>RandomContactView</code> classes, and the other with the contact list and the <code>ContactListModel</code>. Each contact data contains an <em>id</em>, <em>name</em> and a <em>URL to an avatar image</em>.</p>



<p><em>Note: Fake data was generated with <a href="https://www.mockaroo.com/?ref=appcoda.com">Mockaroo</a>.</em></p>



<p>Take your time to navigate in the starter project. When you&#x2019;re ready, then keep reading and get prepared to start adding the missing pieces in the project.</p>



<h2 class="wp-block-heading">Getting Started</h2>



<p>Let&#x2019;s start by creating a new Swift file where we&#x2019;ll add the implementation that we&#x2019;ll do here. Press Cmd+N in your keyboard, select the Swift file template under the Source category, and then continue to create the new file. Name it <em>FetchableImage.swift</em>. Once it&#x2019;s ready select to open it in the Project Navigator if it doesn&#x2019;t open automatically.</p>



<p>In order to make things easy for us as future users of the protocol that we&#x2019;ll make, as well as for other developers, we&#x2019;ll be based on a main idea: <em>To use the URL of the remote image both for fetching the image from the remote source, and as a file name when saving an image locally after it has been fetched</em>. To perform the latter though we&#x2019;ll need to do some processing in the URL first; we can&#x2019;t have a URL as a file name. Regardless, it won&#x2019;t be necessary to add an additional burden of dealing with custom file names when images exist locally that way; the original URL that is already known will be used for both cases.</p>



<p>We&#x2019;ll see everything in details, but for starters, let&#x2019;s define the custom types that we&#x2019;ll need. Let&#x2019;s begin with the protocol and its extension. We&#x2019;ll name it <code>FetchableImage</code>:</p>



<pre class="wp-block-code"><code>protocol FetchableImage {

}


extension FetchableImage {

}</code></pre>



<p>Now, let&#x2019;s declare the two structures that will help us build it:</p>



<pre class="wp-block-code"><code>struct FetchableImageOptions {

}


fileprivate struct FetchableImageHelper {

}</code></pre>



<p>Note that the <code>FetchableImageHelper</code> structure is marked as file-private. That&#x2019;s because we want it to be visible within this file only, and accessible only by the methods that we&#x2019;ll implement next.</p>



<h2 class="wp-block-heading">Specifying Available Options</h2>



<p>Let&#x2019;s talk a bit now about what the <code>FetchableImageOptions</code> structure will contain. Initially, let me tell you that we&#x2019;re going to add a few stored properties only and no methods; it&#x2019;s up to you to enrich it and add any methods that you might find suitable to exist.</p>



<p>Now, let&#x2019;s focus on the directory where fetched images will be stored into. There are two options here; either have them stored in the <em>documents</em> or in the <em>caches</em> directory. The best practice says that they should be saved in the caches directory, as they can be fetched again if they are deleted by the system (in case of low free space on the device for example). However, there will be cases where it&#x2019;s more appropriate to have a downloaded image stored in the document directory. Since there&#x2019;s not a concrete rule about that and it all depends on the situation that <code>FetchableImage</code> comes to serve, then this is the first setting that we&#x2019;ll allow through the <code>FetchableImageOptions</code>:</p>



<pre class="wp-block-code"><code>struct FetchableImageOptions {
    var storeInCachesDirectory: Bool = true
}</code></pre>



<p>See that we set <code>true</code> as the default value of the <code>storeInCachesDirectory</code> property, so images are automatically saved to caches directory. This can be changed by creating a new <code>FetchableImageOptions</code> object and setting that flag to <code>false</code>.</p>



<p>Next, let&#x2019;s refer to another scenario. In the majority of the the cases we&#x2019;ll be keeping fetched images stored locally. In certain circumstances though we might don&#x2019;t want that to happen; we might want to only fetch but not store locally. To deal with that, let&#x2019;s add one more option where we&#x2019;ll specify if fetched images are allowed to be stored locally or not:</p>



<pre class="wp-block-code"><code>struct FetchableImageOptions {
    ...

    var allowLocalStorage: Bool = true
}</code></pre>



<p>We set <code>true</code> as the default value, because most commonly we&#x2019;ll need fetched images to be saved locally by default.</p>



<p>Finally, one more property that even though we can live without it, we are definitely going to need it later in order to be able to save a new image straight from an app to a local directory. That is the file name of the image:</p>



<pre class="wp-block-code"><code>struct FetchableImageOptions {
    ...

    var customFileName: String?
}</code></pre>



<p>Unless you&#x2019;re saving new images with the <em>FetchableImage</em> protocol, chances are that you won&#x2019;t need to use the <code>customFileName</code> property. It doesn&#x2019;t hurt though to be a bit predictive and provide solutions that we may need in the future.</p>



<h2 class="wp-block-heading">FetchableImageHelper First Bits</h2>



<p>Right above we discussed about the documents and caches directory, but only in a theoretical level. Since we&#x2019;re going to need to access them pretty soon, now it&#x2019;s a good time to specify the URL to both.</p>



<p>In the <code>FetchableImageHelper</code> structure add the next two <em>static</em> properties:</p>



<pre class="wp-block-code"><code>fileprivate struct FetchableImageHelper {
    static var documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    static var cachesDirectoryURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
}</code></pre>



<p>Declaring them as static makes it possible to use them without creating a <code>FetchableImageHelper</code> object, just like that: <code>FetchableImageHelper.cachesDirectoryURL</code>.</p>



<h2 class="wp-block-heading">Adding The First Protocol Method</h2>



<p>After having done the first steps, let&#x2019;s start implementing the <code>FetchableImage</code> protocol. Normally, you&#x2019;d expect to begin with a method that&#x2019;s responsible for fetching a remote image, but that&#x2019;s not the place where we&#x2019;ll start from. First we&#x2019;ll implement a method that returns the URL to the local image. We&#x2019;ll need right next it in order to determine whether an image should be fetched from a remote source or be loaded from a local directory.</p>



<p>Initially, let&#x2019;s declare it in the <code>FetchableImage</code> protocol:</p>



<pre class="wp-block-code"><code>func localFileURL(for imageURL: String?, options: FetchableImageOptions?) -&gt; URL?</code></pre>



<p>This method expects for two parameter values: The first one is the <em>remote URL</em> of the image. Please don&#x2019;t be confused here; <code>imageURL</code> is the URL where the image should be fetched from. The method will return the URL to the local file, if that file exists.</p>



<p>Note that it&#x2019;s declared as an optional, and it can be <code>nil</code> in one case only: If the image&#x2019;s origin is not a remote site, but the image was created and stored locally directly from an app. In that case the <code>customFileName</code> must be provided through a <code>FetchableImageOptions</code> object, and that brings us to the second parameter value.</p>



<p>If the default values that we specified in the <code>FetchableImageOptions</code> properties are in accordance to our needs (store fetched images, save to caches directory, don&#x2019;t use a custom file name), then passing <code>nil</code> is just fine. If one of the options should be altered, then a new <code>FetchableImageOptions</code> object must be given with the proper values being set to the properties.</p>



<p>With the above said, let&#x2019;s pass to the default implementation of the method:</p>



<pre class="wp-block-code"><code>extension FetchableImage {

    func localFileURL(for imageURL: String?, options: FetchableImageOptions? = nil) -&gt; URL? {

    }

}</code></pre>



<p>Even though is not allowed to declare a default parameter value when declaring a method to a protocol, notice above (inside the <code>FetchableImage</code> extension) that we set <code>nil</code> as the default value for the <code>options</code> parameter.</p>



<p>The first thing we have to do is to determine what the containing directory of the file is; document or caches directory. We can determine that through the provided <code>options</code> argument in case it&#x2019;s not <code>nil</code>. If it&#x2019;s <code>nil</code> then the caches directory is the storage directory. But we can handle this a bit more generally and optimally; if <code>options</code> parameter value is <code>nil</code>, then we can initialize a new <code>FetchableImageOptions</code> object and &#x201C;read&#x201D; the default settings specified:</p>



<pre class="wp-block-code"><code>let opt = options != nil ? options! : FetchableImageOptions()</code></pre>



<p>I can tell you from now that the above is something that we&#x2019;ll need to do multiple times next. So instead of writing the above condition again and again, let&#x2019;s just create a new method in the <code>FetchableImageHelper</code> structure that will return the proper object:</p>



<pre class="wp-block-code"><code>static func getOptions(_ options: FetchableImageOptions?) -&gt; FetchableImageOptions {
    return options != nil ? options! : FetchableImageOptions()
}</code></pre>



<p>Make sure that you added the above method in the <code>FetchableImageHelper</code> structure. Simply enough, the given <code>options</code> parameter value is returned by the method if it&#x2019;s not <code>nil</code>. Otherwise, a new <code>FetchableImageOptions</code> object is being returned instead.</p>



<p>Back to the <code>localFileURL(for:options:)</code> method implementation, replace the first line we added before with this:</p>



<pre class="wp-block-code"><code>let opt = FetchableImageHelper.getOptions(options)</code></pre>



<p>Now it&#x2019;s easy to determine the containing directory:</p>



<pre class="wp-block-code"><code>let targetDir = opt.storeInCachesDirectory ?
    FetchableImageHelper.cachesDirectoryURL :
    FetchableImageHelper.documentsDirectoryURL</code></pre>



<p>Knowing the target directory, let&#x2019;s specify the file name of the image. First, let&#x2019;s make sure that the <code>imageURL</code> parameter values is not <code>nil</code>:</p>



<pre class="wp-block-code"><code>guard let urlString = imageURL else {

}        </code></pre>



<p>If it&#x2019;s <code>nil</code> and the code execution falls to the <code>else</code> clause above, then we&#x2019;ll check if there&#x2019;s a custom file name provided in the <code>options</code> argument or not. If not, we return <code>nil</code> from the method; there&#x2019;s nothing else to do without a file name. Otherwise, we append the custom file name to the target directory and we return it altogether as a URL object:</p>



<pre class="wp-block-code"><code>guard let customFileName = opt.customFileName else { return nil }
return targetDir.appendingPathComponent(customFileName)</code></pre>



<p>The above handles the case where the <code>imageURL</code> parameter value is <code>nil</code>. If it&#x2019;s not <code>nil</code>, then we&#x2019;ll generate a file name based on the URL, and eventually we&#x2019;ll return it as a full URL along with the target directory:</p>



<pre class="wp-block-code"><code>guard let imageName = FetchableImageHelper.getImageName(from: urlString) else { return nil }
return targetDir.appendingPathComponent(imageName)</code></pre>



<p><code>getImageName(from:)</code> is a method that we&#x2019;ll implement right next. It will be possible to return a <code>nil</code> value, so a <code>guard</code> statement is necessary here (or use an <code>if-let</code> alternatively).</p>



<p>Before we get to it, here&#x2019;s the <code>localFileURL(for:options:)</code> method in one piece:</p>



<pre class="wp-block-code"><code>func localFileURL(for imageURL: String?, options: FetchableImageOptions? = nil) -&gt; URL? {
    let opt = FetchableImageHelper.getOptions(options)
    let targetDir = opt.storeInCachesDirectory ?
        FetchableImageHelper.cachesDirectoryURL :
        FetchableImageHelper.documentsDirectoryURL

    guard let urlString = imageURL else {
        guard let customFileName = opt.customFileName else { return nil }
        return targetDir.appendingPathComponent(customFileName)
    }

    guard let imageName = FetchableImageHelper.getImageName(from: urlString) else { return nil }
    return targetDir.appendingPathComponent(imageName)
}</code></pre>



<h2 class="wp-block-heading">Generating Image Name From Remote URL</h2>



<p>A remote image URL contains special characters, such as the column and slashes, so it cannot consist of a file name when storing fetched images locally. There are various approaches one could follow here. For example, we could create a <em>hash</em> based on the URL path, but the downside is that we&#x2019;d need to import cryptography frameworks. Or we could just remove all special characters and keep the alphanumeric part of the URL only. We could even come up with a custom algorithm to produce a file name based on the original URL.</p>



<p>In this implementation we&#x2019;ll do something different. We&#x2019;ll convert the URL&#x2019;s path to a <em>Base64 encoded</em> string, and then we&#x2019;ll remove any non-alphanumeric characters. This is going to be the file name we&#x2019;ll be using for each image.</p>



<p>Jump to the <code>FetchableImageHelper</code> struct, and define the following method:</p>



<pre class="wp-block-code"><code>static func getImageName(from urlString: String) -&gt; String? {

}</code></pre>



<p>In order to get a Base64 encoded string from the parameter value, we need to convert it first to a Data object as shown next:</p>



<pre class="wp-block-code"><code>guard var base64String = urlString.data(using: .utf8)?.base64EncodedString() else { return nil }
base64String = base64String.components(separatedBy: CharacterSet.alphanumerics.inverted).joined()
return base64String</code></pre>



<p>If the task to create a Data object first and the Base64 encoded representation afterwards does not fail, then we remove all non-alphanumeric characters in the second line. It probably does not look straightforward at first look, but all it does is to <em>break</em> the Base64 encoded string to an array based on the the non-alphanumeric characters (we get them by inverting the alphanumeric character set), and then to <em>rejoin</em> the separated pieces back to one string again.</p>



<p>The above small implementation is fine, however there&#x2019;s a catch; depending on the length of the URL, we might end up with really long Base64 string values.</p>



<p>To work around that, we&#x2019;ll add a check in the method. If <code>base64String</code> is longer than 50 characters long, then we&#x2019;ll drop the first characters and we&#x2019;ll keep the last 50 only. We won&#x2019;t keep the first characters because all image URLs start pretty much the same way (&#x201C;https://some.url/some_path/&#x2026;&#x201D;). The fact that we keep 50 characters instead of 10 or 20 ensures that there will be different characters in the resulting Base64 value.</p>



<p>So, before the <code>return</code> statement above add the following:</p>



<pre class="wp-block-code"><code>guard base64String.count &lt; 50 else {
    return String(base64String.dropFirst(base64String.count - 50))
}</code></pre>



<p>Here&#x2019;s the entire method now:</p>



<pre class="wp-block-code"><code>static func getImageName(from urlString: String) -&gt; String? {
    guard var base64String = urlString.data(using: .utf8)?.base64EncodedString() else { return nil }
    base64String = base64String.components(separatedBy: CharacterSet.alphanumerics.inverted).joined()

    guard base64String.count &lt; 50 else {
        return String(base64String.dropFirst(base64String.count - 50))
    }

    return base64String
}</code></pre>



<h2 class="wp-block-heading">Fetching An Image</h2>



<p>Time to implement one of the core methods of the <code>FetchableImage</code> protocol, maybe the most important one. In the <code>FetchableImage</code> protocol add the following declaration:</p>



<pre class="wp-block-code"><code>func fetchImage(from urlString: String?, options: FetchableImageOptions?, completion: @escaping (_ imageData: Data?) -&gt; Void)</code></pre>



<p>And in the protocol&#x2019;s extension let&#x2019;s start implementing it:</p>



<pre class="wp-block-code"><code>extension FetchableImage {
    ...

    func fetchImage(from urlString: String?, options: FetchableImageOptions? = nil, completion: @escaping (_ imageData: Data?) -&gt; Void) {

    }
}</code></pre>



<p>Although we call it &#x201C;fetchImage&#x201D;, this method won&#x2019;t fetch remote images only; it will load images from local files as well. So, depending on the context, when saying fetching from now on we&#x2019;ll be referring either to remote image fetching only, or both remote fetching and loading from a local file too.</p>



<p>Let&#x2019;s take a look at its parameters for a moment. The first one is the URL of the remote image as a String value. It&#x2019;s declared as an optional in order to cover the case of images not fetched from a remote site, but created and saved by the app locally; there will be no remote URL in this case.</p>



<p>The second parameter value is once again a <code>FetchableImageOptions</code> optional object. By default is <code>nil</code>, considering that the default values will consist of the desirable configuration most of the times.</p>



<p>Lastly, there&#x2019;s the completion handler. Remember that fetching a remote image must be an asynchronous process, as there are many factors that can affect the download process (such as image size, network speed, and more) and therefore an image cannot be returned in real time; required fetching time is undetermined. The parameter value of the completion handler (<code>imageData</code>) is an optional Data object. If fetching an image from a remote source is successful, then we&#x2019;ll pass its data to the completion handler. If it fails, we&#x2019;ll just pass <code>nil</code>.</p>



<p><em><strong>Note #1:</strong> We could have used the Result type introduced in Swift 5 as the parameter value of the completion handler and in case of failure to pass the actual error occurred: <code>Result&lt;Data, Error&gt;</code>. However, we&#x2019;ll stick to the above approach for simplicity.</em></p>



<p><em><strong>Note #2:</strong> We&#x2019;ll pass the fetched (or loaded) image to the completion handler as a Data object. Instead of that, we could have a UIImage object, or a CGImage object, or even a NSImage object if we&#x2019;re talking about macOS. However, we&#x2019;re trying to implement a generic solution here, flexible enough to work with UIKit, SwiftUI, even AppKit on macOS. Passing a Data object to the completion handler consists of the most general solution, since data can be converted to the most appropriate object afterwards.</em></p>



<p>With the above being said, the first step in the method&#x2019;s implementation is to make sure that we&#x2019;re working on a background thread. That&#x2019;s important, as we don&#x2019;t want to block the <a href="https://www.appcoda.com/grand-central-dispatch/">main thread</a> for as long as the image fetching is in progress:</p>



<pre class="wp-block-code"><code>DispatchQueue.global(qos: .background).async {

}</code></pre>



<p>The next two steps involve getting the options (either from the <code>options</code> argument, or from a new <code>FetchableImageOptions</code> object if it&#x2019;s <code>nil</code>), and the URL to the local file of the image:</p>



<pre class="wp-block-code"><code>let opt = FetchableImageHelper.getOptions(options)
let localURL = self.localFileURL(for: urlString, options: options)</code></pre>



<p>You can see here that we&#x2019;re using the <code>getOptions(_:)</code> method we implemented earlier once again, and we&#x2019;re making use of the <code>localFileURL(for:options:)</code> even from the beginning of this method.</p>



<p>What&#x2019;s coming next is important. First, we&#x2019;ll check if the image exists locally. If that&#x2019;s true, then we&#x2019;ll try to load it from the local file and pass its data to the completion handler. If the image does not exist locally, or the <code>allowLocalStorage</code> property of the <code>options</code> argument has been set to <code>false</code> (meaning that the image with the given URL is not allowed to be stored locally), then we&#x2019;ll fetch it using the URL. So, here we go:</p>



<pre class="wp-block-code"><code>if opt.allowLocalStorage,
    let localURL = localURL,
    FileManager.default.fileExists(atPath: localURL.path) {

} else {

}</code></pre>



<p>Inside the <code>if</code> body which is the case of an image existing locally, we&#x2019;ll call another method that will perform the actual loading from the file using the <code>localURL</code> value:</p>



<pre class="wp-block-code"><code>let loadedImageData = FetchableImageHelper.loadLocalImage(from: localURL)</code></pre>



<p>We&#x2019;ll implement the <code>loadLocalImage(from:)</code> pretty soon. <code>loadedImageData</code> will contain either the actual image as a Data object, or <code>nil</code> of something has gone wrong and no image data could be read from the file. In any case, we can pass the <code>loadedImageData</code> to the completion handler right after the above line:</p>



<pre class="wp-block-code"><code>completion(loadedImageData)</code></pre>



<p>In the <code>else</code> body now, let&#x2019;s take care of the case where the image does not exist locally and must be fetched from the given remote URL. Keep in mind that the URL is given as a String value though, so we must create a <code>URL</code> object using it:</p>



<pre class="wp-block-code"><code>guard let urlString = urlString, let url = URL(string: urlString) else {
    completion(nil)
    return
}</code></pre>



<p>If the code execution ends up to the <code>else</code> case and the <code>urlString</code> parameter value is <code>nil</code>, or if it&#x2019;s not a valid URL and the <code>url</code> object cannot be initialized, then we just pass <code>nil</code> to the completion handler; there&#x2019;s nothing more to do.</p>



<p>On the other hand, if <code>url</code> object is initialized successfully, then we can download the image from the remote URL. Actual download code will be implemented to another method just like the <code>loadLocalImage(from:)</code>, but for now let&#x2019;s use it and we&#x2019;ll deal with the missing methods in a while.</p>



<pre class="wp-block-code"><code>FetchableImageHelper.downloadImage(from: url) { (imageData) in

}</code></pre>



<p>The <code>downloadImage(from:completion:)</code> method that we&#x2019;re about to implement soon, accepts the URL that the image should be downloaded from, and a completion handler that gets called when download has finished. That completion handler contains the actual image data on success, or <code>nil</code> in case of error.</p>



<p>Inside the body of the completion handler we must perform two distinct tasks:</p>



<ol><li>To save the fetched image data locally, if allowed.</li><li>To pass the <code>imageData</code> data (or <code>nil</code>) to the completion handler.</li></ol>



<p>Here are both:</p>



<pre class="wp-block-code"><code>FetchableImageHelper.downloadImage(from: url) { (imageData) in
    if opt.allowLocalStorage, let localURL = localURL {
        try? imageData?.write(to: localURL)
    }

    completion(imageData)
}</code></pre>



<p>And the <code>fetchImage(from:options:completion:)</code> method is now complete. There are two missing methods we&#x2019;re using here and we&#x2019;re going to add next, but before doing so, here&#x2019;s the entire method implemented:</p>



<pre class="wp-block-code"><code>func fetchImage(from urlString: String?, options: FetchableImageOptions? = nil, completion: @escaping (_ imageData: Data?) -&gt; Void) {
    DispatchQueue.global(qos: .background).async {

        let opt = FetchableImageHelper.getOptions(options)
        let localURL = self.localFileURL(for: urlString, options: options)

        // Determine if image exists locally first.
        if opt.allowLocalStorage,
            let localURL = localURL,
            FileManager.default.fileExists(atPath: localURL.path) {

            // Image exists locally!
            // Load it using the composed localURL.
            let loadedImageData = FetchableImageHelper.loadLocalImage(from: localURL)
            completion(loadedImageData)

        } else {
            // Image does not exist locally!
            // Download it.

            guard let urlString = urlString, let url = URL(string: urlString) else {
                completion(nil)
                return
            }

            FetchableImageHelper.downloadImage(from: url) { (imageData) in
                if opt.allowLocalStorage, let localURL = localURL {
                    try? imageData?.write(to: localURL)
                }

                completion(imageData)
            }

        }
    }
}</code></pre>



<h2 class="wp-block-heading">Performing The Actual Image Download</h2>



<p>We&#x2019;ll implement the missing methods starting from the most recent one, the one that performs the actual image download. In it, we&#x2019;ll simply initialize a <code>URLSession</code> object and through that, we&#x2019;ll use a <em>data task</em> in order to fetch the image data from the specified URL. If you&#x2019;ve ever used <code>URLSession</code> before, then the following implementation will look familiar. Just make sure to add the next implementation in the <code>FetchableImageHelper</code> structure:</p>



<pre class="wp-block-code"><code>static func downloadImage(from url: URL, completion: @escaping (_ imageData: Data?) -&gt; Void) {
    let sessionConfiguration = URLSessionConfiguration.ephemeral
    let session = URLSession(configuration: sessionConfiguration)
    let task = session.dataTask(with: url) { (data, response, error) in
        completion(data)
    }
    task.resume()
}</code></pre>



<p>Notice that we don&#x2019;t mind about the response or the potential error coming back from the server here. However, you&#x2019;re free to update the above code and handle them too if they&#x2019;re important to you. The only thing we&#x2019;re doing here is to call the completion handler passing the fetched data to it.</p>



<h2 class="wp-block-heading">Loading A Local Image File</h2>



<p>With the <code>downloadImage(from:completion:)</code> in place, let&#x2019;s pass to the other currently missing method; the <code>loadLocalImage(from:)</code> that we already made use of in the <code>fetchImage(from:options:completion:)</code> method previously.</p>



<p>Inside its body we&#x2019;re going to perform a simple action; we&#x2019;ll try to initialize a Data object using the contents of the file specified by the given URL. On success, we&#x2019;ll return the initialized data object which is nothing else but the image data. On failure, we&#x2019;ll just return <code>nil</code>. Once again, we&#x2019;re adding this implementation to the <code>FetchableImageHelper</code> structure:</p>



<pre class="wp-block-code"><code>static func loadLocalImage(from url: URL) -&gt; Data? {
    do {
        let imageData = try Data(contentsOf: url)
        return imageData
    } catch {
        print(error.localizedDescription)
        return nil
    }
}</code></pre>



<h2 class="wp-block-heading">Trying Out Image Fetching</h2>



<p>Time to try out what we&#x2019;ve done so far! In the starter project you&#x2019;ve downloaded, you&#x2019;ll find a file called <em>RandomContactModel.swift</em>. Spot it in the Project Navigator and click to open it.</p>



<p>The first thing that <code>RandomContactModel</code> class does is to load the fake contacts from the <em>fakedata_small.json</em> file, decode the JSON data and populate decoded data to the collection of <code>Contact</code> objects, called <code>contacts</code>.</p>



<p>It also contains a method called <code>pickRandomContact()</code> that selects randomly a <code>Contact</code> object from the collection of contacts. The selected contact will be displayed in the <code>UserView</code> view, which is embedded in the <code>RandomContactView</code>. For every contact, the avatar image will be fetched either from a remote or a local source and when it&#x2019;ll become available the UI will be updated to display it.</p>



<p>Currently, the picker method does nothing fancy except for just picking a random contact as you can see in the <code>pickRandomContact()</code> method implementation:</p>



<pre class="wp-block-code"><code>func pickRandomContact() {
    let random = Int.random(in: 0..&lt;10)
    guard random &lt; contacts.count else { return }
    contact = contacts[random]
}</code></pre>



<p>Since we want to use the <code>FetchableImage</code> protocol here, the first step we necessarily need to do is to make <code>RandomContactModel</code> class conform to it:</p>



<pre class="wp-block-code"><code>class RandomContactModel: ObservableObject, FetchableImage {
    ...
}</code></pre>



<p>In the <code>pickRandomContact()</code> method, we can now call the <code>fetchImage(from:options:completion:)</code> method in order to fetch the image matching to the <code>avatarURL</code> property of the randomly picked contact object:</p>



<pre class="wp-block-code"><code>func pickRandomContact() {
    ...

    fetchImage(from: contact.avatarURL, options: nil) { (avatarData) in

    }
}</code></pre>



<p>At the time being we pass no options, so the default ones will be used (images will be stored to the caches directory, storing remote images is allowed and no custom file names will be used).</p>



<p>Based on the logic we applied earlier, the above method will first try to load the image from a local file. If it doesn&#x2019;t exist, then it&#x2019;ll try to fetch it, and then store it to the caches directory for future use. In suqsequent calls of the method, the image will be loaded from the local file, so the display time will be remarkably smaller. We&#x2019;ll see all that in action.</p>



<p>Since it&#x2019;s convenient to work with <code>CGImage</code> images in <code>Image</code> controls in SwiftUI, we&#x2019;ll first make sure that the <code>avatarData</code> is not <code>nil</code> and then we&#x2019;ll try to initialize a <code>UIImage</code> object from that data. Then, from the UIImage object we&#x2019;ll get the <code>CGImage</code> representation we&#x2019;re looking for. Something important to note is that we must use the main thread in order to do what I just described. Remember that image fething takes place in the background, and altering the UI is only allowed from the main thread of the app.</p>



<pre class="wp-block-code"><code>func pickRandomContact() {
    ...

    fetchImage(from: contact.avatarURL, options: nil) { (avatarData) in
        if let data = avatarData {
            DispatchQueue.main.async {
                self.contact.avatar = UIImage(data: data)?.cgImage
            }
        }
    }
}</code></pre>



<p>The avatar <code>CGImage</code> representation is assigned to the <code>avatar</code> property of the randomly selected contact. Since it&#x2019;s marked as <code>@Published</code>, that change will trigger the UI to be updated in the <code>UserView</code> view.</p>



<p>Now, open the <code>RandomContactView</code> and add the following line as the action of the button:</p>



<pre class="wp-block-code"><code>Button(&quot;Random contact&quot;) {
    self.randomDataModel.pickRandomContact()
}</code></pre>



<p>And&#x2026; run the app to see the results! By default, each fake contact has a default avatar indicating the lack of the proper one. Click on the <em>Random Contact</em> button to pick a random contact, and see that within a few seconds the image will be fetched and displayed on the <code>Image</code> control. Keep clicking the button, so more images for more contacts to be fetched. Then, stop and run the app again so the <code>avatar</code> property of each contact becomes empty again. You&#x2019;ll see that fetching images that have been downloaded already is almost instant; they&#x2019;re loaded from the local file!</p>



<p>If you want to see the stored images, go to the <code>pickRandomContact()</code> method, and right before the <code>fetchImage</code> method call add the following print command:</p>



<pre class="wp-block-code"><code>func pickRandomContact() {
    ...

    print(localFileURL(for: contact.avatarURL))

    fetchImage(from: contact.avatarURL, options: nil) { (avatarData) in
        ...
    }
}</code></pre>



<p>Run again and start tapping on the <em>Random Contact</em> button. This time, you&#x2019;ll see in the console the URLs to local image files. Copy any displayed URL, but make sure <em>not</em> to include the prefix &#x201C;file://&#x201D; and the file name (stop in &#x201C;Caches/&#x201D;). Go to Finder and press Shift+Cmd+G, then paste the copied URL and press Return. That&#x2019;s also a good chance to see the generated image names.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="720" height="576" src="https://www.appcoda.com/content/images/wordpress/2020/06/t72_1_try_random_contact.gif" alt="Best Practice: How to Fetch Remote Images in Swift Projects" class="wp-image-18175"></figure>



<p>You can also play around with the options. Delete all downloaded files, and before calling the <code>fetchImage</code> method create the following <code>FetchableImageOptions</code> object. Pass it as the second argument in the <code>fetchImage</code> call:</p>



<pre class="wp-block-code"><code>let options = FetchableImageOptions(storeInCachesDirectory: true, allowLocalStorage: false, customFileName: nil)

func pickRandomContact() {
    ...

    let options = FetchableImageOptions(storeInCachesDirectory: true, allowLocalStorage: false, customFileName: nil)

    fetchImage(from: contact.avatarURL, options: options) { (avatarData) in
        ...
    }
}</code></pre>



<p>By running again you&#x2019;ll see that no images are stored anymore locally, and every time you ask for a random contact its avatar is being fetched again.</p>



<p>Let&#x2019;s try something else. Update the above code with this:</p>



<pre class="wp-block-code"><code>func pickRandomContact() {
    ...

    // let options = FetchableImageOptions(storeInCachesDirectory: true, allowLocalStorage: false, customFileName: nil)
    let options = FetchableImageOptions(storeInCachesDirectory: false, allowLocalStorage: true, customFileName: nil)

    fetchImage(from: contact.avatarURL, options: options) { (avatarData) in
        ...
    }
}</code></pre>



<p>In this configuration we allow local storage, but we set <code>false</code> to the first parameter value of the <code>FetchableImageOptions</code> initializer. Images will be stored to documents directory instead of caches directory.</p>



<p>Run and see that this time contact avatars are stored in the documents directory indeed.</p>



<h2 class="wp-block-heading">Fetching Batch Images</h2>



<p>Let&#x2019;s move on and let&#x2019;s make <code>FetchableImage</code> protocol capable of fetching multiple images as well. The good news is that we&#x2019;ll be based on what we&#x2019;ve built so far, so fetching batch images shouldn&#x2019;t be intimidating. Initially, we&#x2019;ll declare a new method in the <code>FetchableImage</code> protocol (switch to the <em>FetchableImage.swift</em> file):</p>



<pre class="wp-block-code"><code>protocol FetchableImage {
    func fetchBatchImages(using urlStrings: [String?], options: FetchableImageOptions?,
         partialFetchHandler: @escaping (_ imageData: Data?, _ index: Int) -&gt; Void,
         completion: @escaping () -&gt; Void)
}</code></pre>



<p>Before we start implementing it in the protocol&#x2019;s extension, let&#x2019;s see the parameter values we&#x2019;re setting here. First, it&#x2019;s the collection of URLs as String values; we want to fetch multiple images, therefore we need multiple URLs. Next, we have the options that we&#x2019;ve talked about many times so far.</p>



<p>What&#x2019;s new and interesting here is the third parameter value, the <code>partialFetchHandler</code>. You might think of it as a progress handler as well. Imagine that you have to download a big number of images, and that task is going to take some time. Most probably you&#x2019;ll want to keep your users informed about the download progress by showing a progress bar or a relevant message. This handler makes that possible. Every time an image is fetched, its data will be given as the first argument to this handler, with the second argument being the index of the image in the collection of all images. That way we will have every single image at our disposal right when it becomes available, and with the index we&#x2019;ll be able to show the progress that has been made at any given moment.</p>



<p>Finally, the last parameter value it&#x2019;s a completion that will be called when the overall process is finished. Notice that we pass no image data here; that happens in the <code>partialFetchHandler</code>.</p>



<p>Let&#x2019;s go to the implementation part now. In the <code>FetchableImage</code> extension add the method definition:</p>



<pre class="wp-block-code"><code>extension FetchableImage {
    func fetchBatchImages(using urlStrings: [String?], options: FetchableImageOptions?,
         partialFetchHandler: @escaping (_ imageData: Data?, _ index: Int) -&gt; Void,
         completion: @escaping () -&gt; Void) {



    }
}</code></pre>



<p>Now, an important clarification. We&#x2019;ll fetch multiple images <em>recursively</em>, meaning we&#x2019;ll be calling the same method to fetch an image again and again until all images have been fetched. That method won&#x2019;t be the one we just defined; for that purpose, we&#x2019;ll implement a new one.</p>



<p>Still being in the <code>FetchableImage</code> extension, add the next <em>private</em> method. This won&#x2019;t be visible out of the extension, however it&#x2019;ll help us achieve our goal:</p>



<pre class="wp-block-code"><code>private func performBatchImageFetching(using urlStrings: [String?], currentImageIndex: Int,
    options: FetchableImageOptions?,
    partialFetchHandler: @escaping (_ imageData: Data?, _ index: Int) -&gt; Void,
    completion: @escaping () -&gt; Void) {

}</code></pre>



<p>As you notice, the parameters are almost identical to those of the previous method. The new thing here is the second parameter, which is the index of the URL that should be used in the <code>urlStrings</code> collection.</p>



<p>The implementation is fairly simple. At first, it&#x2019;s necessary to make sure that the <code>currentImageIndex</code> is within the <code>urlStrings</code> count range, and proceed if only that&#x2019;s true. Otherwise, we&#x2019;ll just call the completion handler and return from the method:</p>



<pre class="wp-block-code"><code>private func performBatchImageFetching(using urlStrings: [String?], currentImageIndex: Int,
    options: FetchableImageOptions?,
    partialFetchHandler: @escaping (_ imageData: Data?, _ index: Int) -&gt; Void,
    completion: @escaping () -&gt; Void) {

    guard currentImageIndex &lt; urlStrings.count else {
        completion()
        return
    }
}</code></pre>



<p>The next step is to fetch the image pointed by the <code>currentImageIndex</code>. In order to do that, we&#x2019;ll use the <code>fetchImage(from:options:completion:)</code> method that we have already made:</p>



<pre class="wp-block-code"><code>private func performBatchImageFetching(using urlStrings: [String?], currentImageIndex: Int,
    options: FetchableImageOptions?,
    partialFetchHandler: @escaping (_ imageData: Data?, _ index: Int) -&gt; Void,
    completion: @escaping () -&gt; Void) {

    ...

    fetchImage(from: urlStrings[currentImageIndex], options: options) { (imageData) in

    }
}</code></pre>



<p>Inside the body of the above completion handler we&#x2019;ll do two things. First, we&#x2019;ll call the partial handler in order to pass to the caller the image data that was just fetched (or <code>nil</code> if no data exists), and the index of the current image:</p>



<pre class="wp-block-code"><code>private func performBatchImageFetching(using urlStrings: [String?], currentImageIndex: Int,
    options: FetchableImageOptions?,
    partialFetchHandler: @escaping (_ imageData: Data?, _ index: Int) -&gt; Void,
    completion: @escaping () -&gt; Void) {

    ...

    fetchImage(from: urlStrings[currentImageIndex], options: options) { (imageData) in
        partialFetchHandler(imageData, currentImageIndex)
    }
}</code></pre>



<p>The second thing is to call the same method and recursively fetch the next image. What&#x2019;s important to take care of here is the second argument; we pass the <code>currentImageIndex</code> increased by 1 to point to the next image. At the end we&#x2019;ll call the completion handler:</p>



<pre class="wp-block-code"><code>private func performBatchImageFetching(using urlStrings: [String?], currentImageIndex: Int,
    options: FetchableImageOptions?,
    partialFetchHandler: @escaping (_ imageData: Data?, _ index: Int) -&gt; Void,
    completion: @escaping () -&gt; Void) {

    ...

    fetchImage(from: urlStrings[currentImageIndex], options: options) { (imageData) in
        partialFetchHandler(imageData, currentImageIndex)

        self.performBatchImageFetching(using: urlStrings,
            currentImageIndex: currentImageIndex + 1,
            options: options, partialFetchHandler: partialFetchHandler) {
            completion()
        }
    }
}</code></pre>



<p>With that method implemented, we can go back to the <code>fetchBatchImages(using:options:partialFetchHandler:completion:)</code> method that we started making, but we never finished it. Simply enough, in it we&#x2019;ll call the above method indicating the index of the first URL; 0 (zero). At the body of the completion handler of the invoked method, we&#x2019;ll call the completion handler of this one so the caller knows that the entire process has finished.</p>



<pre class="wp-block-code"><code>func fetchBatchImages(using urlStrings: [String?],
                      options: FetchableImageOptions? = nil,
                      partialFetchHandler: @escaping (_ imageData: Data?, _ index: Int) -&gt; Void,
                      completion: @escaping () -&gt; Void) {

    performBatchImageFetching(using: urlStrings, currentImageIndex: 0,
        options: options, partialFetchHandler: { (imageData, index) in

        partialFetchHandler(imageData, index)

    }) {
        completion()
    }

}</code></pre>



<p>And with that we finish the necessary work in order to enable multiple image fetching. As you understand, all the essential stuff was already made. Here we focused only on the recursion and on using the code that already works.</p>



<h2 class="wp-block-heading">Trying Out Fetching Multiple Images</h2>



<p>So, now that <code>FetchableImage</code> is capable of fetching batch images, let&#x2019;s give it a try and see that it actually works. To start, open the <em>ContactListModel.swift</em> file where you&#x2019;ll find the <code>ContactListModel</code> class. What&#x2019;s already implemented here is the loading and decoding of the fake contact data, read this time by the <em>fakedata.json</em> file that exists in the demo project.</p>



<p>Notice here that there are three observed properties marked as <code>@Published</code>:</p>



<ol><li><code>contacts</code>: An array of <code>Contact</code> objects that contains the fake contact data.</li><li><code>progress</code>: A Double value that will keep the download progress. Any change on this property will lead to visual update of the progress bar (implemented in the <code>ProgressView</code>, but embedded in the <code>ContactListView</code>).</li><li><code>isFetching</code>: A flag indicating whether a download process is taking place or not. We&#x2019;re going to need it in order to show or hide the progress, as well as to prevent starting a new download process while another one is already in progress.</li></ol>



<p>Let&#x2019;s fetch batch images now. First, adopt the <code>FetchableImage</code> protocol:</p>



<pre class="wp-block-code"><code>class ContactListModel: ObservableObject, FetchableImage {
    ...
}</code></pre>



<p>Next, implement a new method called <code>fetchAvatars()</code>. First we&#x2019;ll make sure that <code>isFetching</code> is <code>false</code>, and if so we&#x2019;ll turn it to <code>true</code> and we&#x2019;ll initialize the <code>progress</code> value:</p>



<pre class="wp-block-code"><code>func fetchAvatars() {
    guard !isFetching else { return }
    isFetching = true
    progress = 0.0
}</code></pre>



<p>Next, let&#x2019;s create a collection of all avatar URLs:</p>



<pre class="wp-block-code"><code>func fetchAvatars() {
    ...

    let allAvatarURLs = contacts.map { $0.avatarURL }
}</code></pre>



<p>Time to call the <code>fetchBatchImages(using:options:partialFetchHandler:completion:)</code> method in order to initiate the batch image fetching:</p>



<pre class="wp-block-code"><code>func fetchAvatars() {
    ...

    fetchBatchImages(using: allAvatarURLs, options: nil, partialFetchHandler: { (imageData, index) in

        DispatchQueue.main.async {
            guard let data = imageData else { return }
            self.contacts[index].avatar = UIImage(data: data)?.cgImage

            self.progress = Double(((index + 1) * 100) / self.contacts.count)
        }

    }) {
        print(&quot;Finished fetching avatars!&quot;)

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.4, execute: {
            self.isFetching = false
        })
    }
}</code></pre>



<p>See what happens every time the partial handler is called:</p>



<ul><li>First, we switch to the main thread necessarily because image fetching is taking place in the background.</li><li>Second, we make sure that there&#x2019;s image data fetched and the returned value is not <code>nil</code>.</li><li>Third, and probably most importantly, we use the index of the image in order to access the matching object in the <code>contacts</code> array and update its avatar. That action will make the UI get updated and display the avatar image.</li><li>Finally, we calculate the progress as a percentage. This will update the progress bar.</li></ul>



<p>Once all downloads are finished, the completion handler is called. Besides the non-important <code>print</code> statement which exists just for verification purposes, we switch the value of the <code>isFetching</code> property back to <code>false</code>. This is taking place on the main thread because it will affect the UI; it&#x2019;ll make the progress bar become hidden. The small delay of 0.4 seconds is there just for the pleasure of the eye, so the progress bar does not disappear instantly right after the last image fetching.</p>



<p>Open the <em>ContactListView.swift</em> file now, and spot the button that works as the first navigation item. There we&#x2019;ll call the <code>fetchAvatars()</code> method:</p>



<pre class="wp-block-code"><code>.navigationBarItems(
    leading:
    Button(action: {

        // Add this line:
        self.contactList.fetchAvatars()

    }) {
        Image(systemName: &quot;arrow.clockwise&quot;)
    },</code></pre>



<p>Run the app, and open the second tab. You&#x2019;ll see a long list of fake contacts having the default avatar image. Tap on the refresh button, and see the avatars gradually being updated. On next run, you&#x2019;ll find out that avatars will be shown almost instantly; that&#x2019;s because they&#x2019;re stored locally.</p>



<p><em>Note: We could have avatars being fetched automatically, but to make it easier to try out what we&#x2019;re building we keep it as a manual action that gets triggered with the refresh bar button item.</em></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="720" height="576" src="https://www.appcoda.com/content/images/wordpress/2020/06/t72_2_batch_fetch.gif" alt="Best Practice: How to Fetch Remote Images in Swift Projects" class="wp-image-18176"></figure>



<h2 class="wp-block-heading">Deleting Single Local Image Files</h2>



<p>Fetching images is out of our way now, so let&#x2019;s focus on the opposite actions for a while. Let&#x2019;s make it possible to remove either single or batch image files from a local directory, and let&#x2019;s start in this part with the first one.</p>



<p>Back to the <em>FetchableImage.swift</em> file, let&#x2019;s declare the following new method:</p>



<pre class="wp-block-code"><code>protocol FetchableImage {
    ...

    func deleteImage(using imageURL: String?, options: FetchableImageOptions?) -&gt; Bool
}</code></pre>



<p>Whatever we&#x2019;ve discussed about the image URL and options applies here too, so I&#x2019;m skipping any kind of further discussion about them. However, see that this time there&#x2019;s not a completion handler here. Instead, the deletion result is returned instantly from the method as a Boolean value. On successful deletion it&#x2019;ll return <code>true</code>, otherwise it&#x2019;ll return <code>false</code>.</p>



<p>Let&#x2019;s jump to its implementation now. In the <code>FetchableImage</code> extension we&#x2019;ll start by finding the URL to the local image:</p>



<pre class="wp-block-code"><code>extension FetchableImage {
    ...

    func deleteImage(using imageURL: String?, options: FetchableImageOptions? = nil) -&gt; Bool {
        guard let localURL = localFileURL(for: imageURL, options: options),
            FileManager.default.fileExists(atPath: localURL.path) else { return false }
    }
}</code></pre>



<p>If the URL to the local image is <code>nil</code>, or the file cannot be found, we just return <code>false</code> and we stop here. Otherwise, we try to delete the image file in a <code>do-catch</code> statement as shown next:</p>



<pre class="wp-block-code"><code>func deleteImage(using imageURL: String?, options: FetchableImageOptions? = nil) -&gt; Bool {
    ...

    do {
        try FileManager.default.removeItem(at: localURL)
        return true
    } catch {
        print(error.localizedDescription)
        return false
    }
}</code></pre>



<p>And that&#x2019;s all. We can now go to try out single image deletion.</p>



<h2 class="wp-block-heading">Trying Out Deleting Single Images</h2>



<p>When using the demo app, then by tapping on a contact&#x2019;s row in the list (second tab) you&#x2019;re navigating to a details page. That&#x2019;s nothing more than the contact&#x2019;s avatar, name, and a button that allows to delete the avatar image. Actually, you&#x2019;ll find out soon that the button has a double role. When the contact&#x2019;s avatar exists, it allows to delete it. In the opposite case, it will be used to fetch it again.</p>



<p>So, here&#x2019;s the place where we&#x2019;ll test the image deletion. Before we get to the button though, open the <em>ContactListModel.swift</em> file where it&#x2019;s necessary to add a couple of new methods. In the first one we&#x2019;ll call the <code>deleteImage(using:options:)</code> method we implemented right above:</p>



<pre class="wp-block-code"><code>func deleteAvatar(for contact: Contact) {
    guard let index = contacts.firstIndex(where: { $0.id == contact.id }) else { return }

    if deleteImage(using: contacts[index].avatarURL, options: nil) {
        contacts[index].avatar = nil
    }
}</code></pre>



<p>The brand new <code>deleteAvatar(for:)</code> method gets a <code>Contact</code> object as an argument, and based on that it tries to find its index among all <code>Contact</code> objects in the <code>contacts</code> array. Then, it calls the <code>deleteImage(using:options:)</code> method of the <code>FetchableImage</code> protocol, and on success it removes the actual avatar image by setting <code>nil</code> to the respective property.</p>



<p>The next method we&#x2019;ll add in the <code>ContactListModel</code> class is necessary only to let us make the button in the <code>ContactDetailsView</code> have the double role I mentioned previously; delete and fetch. There&#x2019;s nothing new that we haven&#x2019;t discussed about already, so I&#x2019;m presenting it at once:</p>



<pre class="wp-block-code"><code>func fetchAvatar(for contact: Contact, completion: @escaping (_ avatar: CGImage?) -&gt; Void) {
    guard let index = contacts.firstIndex(where: { $0.id == contact.id }) else { return }

    fetchImage(from: contacts[index].avatarURL) { (imageData) in
        DispatchQueue.main.async {
            guard let data = imageData else { return }
            self.contacts[index].avatar = UIImage(data: data)?.cgImage
            completion(self.contacts[index].avatar)
        }
    }
}</code></pre>



<p>Open the <em>ContactDetailsView.swift</em> now, and update the following:</p>



<pre class="wp-block-code"><code>Button(contact.avatar != nil ? &quot;Delete Avatar&quot; : &quot;Fetch Avatar&quot;) {

}</code></pre>



<p>with this:</p>



<pre class="wp-block-code"><code>Button(contact.avatar != nil ? &quot;Delete Avatar&quot; : &quot;Fetch Avatar&quot;) {
    if self.contact.avatar != nil {
        self.contact.avatar = nil
        self.contactList.deleteAvatar(for: self.contact)
    } else {
        self.contactList.fetchAvatar(for: self.contact) { (fetchedAvatar) in
            guard let avatar = fetchedAvatar else { return }
            self.contact.avatar = avatar
        }
    }
}</code></pre>



<p>Finally, run the app. Go to the details of a contact, and use the button you&#x2019;ll find there. If the avatar already exists, it&#x2019;ll be deleted, otherwise it&#x2019;ll be fetched and displayed.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="720" height="576" src="https://www.appcoda.com/content/images/wordpress/2020/06/t72_3_delete_single.gif" alt="Best Practice: How to Fetch Remote Images in Swift Projects" class="wp-image-18177"></figure>



<h2 class="wp-block-heading">Deleting Multiple images</h2>



<p>Now that single image deletion is working, we can easily add a new method in the <code>FetchableImage</code> protocol that will be deleting multiple images. And I&#x2019;m saying easily, because we&#x2019;ll be based on the single deletion method we implemented right before.</p>



<p>Open the <em>FetchableImage.swift</em> file, and add the following method declaration in the <code>FetchableImage</code> protocol:</p>



<pre class="wp-block-code"><code>protocol FetchableImage {
    ...

    func deleteBatchImages(using imageURLs: [String?], options: FetchableImageOptions?)
}</code></pre>



<p>Then, in the protocol&#x2019;s extension implement it. It&#x2019;s as simple as it can get:</p>



<pre class="wp-block-code"><code>extension FetchableImage {
    ...

    func deleteBatchImages(using imageURLs: [String?], options: FetchableImageOptions? = nil) {
        DispatchQueue.global().async {
            imageURLs.forEach { _ = self.deleteImage(using: $0, options: options) }
        }
    }
}</code></pre>



<p>First, we use the global background thread for our task. Then, using the <code>forEach</code> higher order function we go through all image URLs provided in the first parameter value, and we&#x2019;re deleting one by one all image files.</p>



<p><em>Note: Read more about higher order functions <a href="https://www.appcoda.com/higher-order-functions-swift/">here</a>.</em></p>



<p>Notice that the above implementation is based on the assumption that the <code>imageURLs</code> parameter value contains the URLs of the images that should be deleted. It won&#x2019;t work in case we wanted to delete multiple files with custom file names provided to the <code>customFileName</code> property of equal number of <code>FetchableImageOptions</code> objects. In such scenario, we would need to create a new method:</p>



<pre class="wp-block-code"><code>protocol FetchableImage {
    ...

    func deleteBatchImages(using multipleOptions: [FetchableImageOptions])
}</code></pre>



<p>And the implementation in the protocol&#x2019;s extension:</p>



<pre class="wp-block-code"><code>func deleteBatchImages(using multipleOptions: [FetchableImageOptions]) {
    DispatchQueue.global().async {
        multipleOptions.forEach { _ = self.deleteImage(using: nil, options: $0) }
    }
}</code></pre>



<p>As you understand, each <code>FetchableImageOptions</code> item in the <code>multipleOptions</code> array will match to a single file with custom file name.</p>



<h2 class="wp-block-heading">Trying Out Batch Image Deletion</h2>



<p>We are going to try out here the batch deletion of images based on URLs, so open the <em>ContactListModel.swift</em> file where it&#x2019;s necessary to add one new method in the <code>ContactListModel</code> class:</p>



<pre class="wp-block-code"><code>func deleteAllAvatars() {

}</code></pre>



<p>In it, we&#x2019;ll create an array of all avatar URLs, then we&#x2019;ll call the method we just implemented in order to delete all local image files, and finally we&#x2019;ll iterate through all contact objects in the <code>contacts</code> array to set <code>nil</code> to all avatar objects:</p>



<pre class="wp-block-code"><code>func deleteAllAvatars() {
    let allAvatarURLs = contacts.map { $0.avatarURL }
    deleteBatchImages(using: allAvatarURLs, options: nil)
    for (index, _) in contacts.enumerated() {
        contacts[index].avatar = nil
    }
}</code></pre>



<p>Finally, go to the <em>ContactListView.swift</em> file, and find the second bar button. In the action closure call the <code>deleteAllAvatars()</code>:</p>



<pre class="wp-block-code"><code>.navigationBarItems(
    leading:
    ...,

    trailing:
    Button(action: {

        // Add this line:
        self.contactList.deleteAllAvatars()

    }) {
        Image(systemName: &quot;trash&quot;)
    }
)</code></pre>



<p>Run the app and tap on the trash button in the contacts list if you&#x2019;ve already fetched remote avatar images. All avatars will be removed, and you&#x2019;ll need to tap on the refresh button to fetch them again.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="720" height="576" src="https://www.appcoda.com/content/images/wordpress/2020/06/t72_4_multiple_delete.gif" alt="Best Practice: How to Fetch Remote Images in Swift Projects" class="wp-image-18178"></figure>



<h2 class="wp-block-heading">Saving A Custom Image</h2>



<p>There&#x2019;s one last thing left to be done, and that is to add one last method in the <code>FetchableImage</code> protocol that will make it easy for us to save an image locally straight from the app, instead of fetching it from a remote source. That last method is not something that we need in order to use the <code>FetchableImage</code> protocol; however it would be nice to exist, so we can save custom images if necessary without having to come up with new solutions while developing an app.</p>



<p>So, open the <em>FetchableImage.swift</em> file for one last time, and add the next method declaration in the protocol:</p>



<pre class="wp-block-code"><code>protocol FetchableImage {
    ...

    func save(image data: Data, options: FetchableImageOptions) -&gt; Bool
}</code></pre>



<p>Notice here that:</p>



<ol><li>The method accepts the data of the image that we want to save.</li><li>The <code>options</code> parameter value is <em>not</em> optional here; we need it to get the file name!</li></ol>



<p>Let&#x2019;s implement it now in the protocol&#x2019;s extension:</p>



<pre class="wp-block-code"><code>extension FetchableImage {
    ...

    func save(image data: Data, options: FetchableImageOptions) -&gt; Bool {
        guard let url = localFileURL(for: nil, options: options) else { return false }
        do {
            try data.write(to: url)
            return true
        } catch {
            print(error.localizedDescription)
            return false
        }
    }
}</code></pre>



<p>If the URL to the actual file name cannot be formed or writing to file fails, we return <code>false</code>. If writing image data to file succeeds though, then we return <code>true</code>.</p>



<p>I leave that last feature for you to test.</p>



<h2 class="wp-block-heading">Summary</h2>



<p><code>FetchableImage</code> protocol is now complete, and that brings us to the end of this post. I hope you enjoyed this step-by-step implementation of a really handy tool, which hopefully will fit in your own projects. </p>



<p>If you haven&#x2019;t implemented your own solution in order to deal with remote images, then you can consider starting with what you read here and to extend or modify it in order to cover your specific needs. </p>



<p><a href="https://github.com/appcoda/FetchableImage?ref=appcoda.com">For reference, you can </a>download the complete project on GitHub.</p>



<p>If you want to go even further, you can make it a reusable library and wrap it up in a <a href="https://www.appcoda.com/swift-package-xcode/">Swift package</a>. Thanks for reading!</p>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[Introduction to MusicKit: Building a Music Player in SwiftUI]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>At WWDC 2017, Apple announced <code><a href="https://developer.apple.com/musickit/?ref=appcoda.com">MusicKit</a></code>, a framework to help developers build apps that allow users to play Apple Music and their local music library. Unlike most frameworks like <code>ARKit</code> or <code>CoreML</code>, <code>MusicKit</code> cannot be added to your code with a simple <code>import</code> function. Rather, it&#x2019;s a combination</p>]]></description><link>https://www.appcoda.com/musickit-music-player-swiftui/</link><guid isPermaLink="false">66612a0f166d3c03cf0114c4</guid><category><![CDATA[iOS Programming]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><dc:creator><![CDATA[Sai Kambampati]]></dc:creator><pubDate>Fri, 03 Apr 2020 17:38:51 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2020/04/uy-9dyz8ppm.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2020/04/uy-9dyz8ppm.jpg" alt="Introduction to MusicKit: Building a Music Player in SwiftUI"><p>At WWDC 2017, Apple announced <code><a href="https://developer.apple.com/musickit/?ref=appcoda.com">MusicKit</a></code>, a framework to help developers build apps that allow users to play Apple Music and their local music library. Unlike most frameworks like <code>ARKit</code> or <code>CoreML</code>, <code>MusicKit</code> cannot be added to your code with a simple <code>import</code> function. Rather, it&#x2019;s a combination of the Apple Music API, the <code>StoreKit</code> framework, the <code>MediaPlayer</code> framework, and some other web-based technologies.</p>



<p>You may be wondering why is this framework so difficult to integrate into your applications compared to other API and frameworks. This is because MusicKit was not only built to work on iOS devices, but Android and Web applications as well. Just like <code>CloudKit</code> or <code>Sign in with Apple</code>, you can access a user&#x2019;s Apple Music account through Android and Web apps. However, for the purpose of this tutorial, we will simply focus on building a music player for iOS using SwiftUI.</p>



<p><em><strong>Editor&#x2019;s note</strong>: This is a two part series of our MusicKit tutorials. This is the first part and the second one will come next week.</em> If you are new to SwiftUI, you can check out <a href="https://www.appcoda.com/swiftui-first-look/">this tutorial</a> and <a href="https://www.appcoda.com/learnswiftui/swiftui-basics.html">this sample chapter</a> of our <a href="https://www.appcoda.com/swiftui">Mastering SwiftUI</a> book.</p>



<h2 class="wp-block-heading">The MusicKit Demo App</h2>



<p>In this tutorial series, we&#x2019;ll be building a very simple music player that searches using the Apple Music API for a song, grabs the relevant details of the song like artist name and album cover, and plays it on the device with the help of <code>MediaPlayer</code>&#x2019;s <code>MPMusicPlayerController</code>. We&#x2019;ll also see how to use the <code>MediaPlayer</code> framework to play, rewind, and skip songs. </p>



<p>Before we can do this, we need to first communicate with the Apple Music service to see if a user has a valid Apple Music subscription. This requires us to create a MusicKit identifier and private key to sign your developer tokens using Certificates, Identifiers &amp; Profiles in our Apple Developer Program account. Since this can be very daunting for a lot of iOS developers, a majority of this tutorial will focus on creating these keys and identifiers. The next part of this tutorial will focus more on the <code>MediaPlayer</code> framework.</p>



<p>Our final app will look like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="997" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-1024x997.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17919" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-1024x997.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-308x300.png 308w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-200x195.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-768x747.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-1536x1495.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-2048x1993.png 2048w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-1680x1635.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-1240x1207.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-860x837.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-680x662.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-400x389.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-1-50x49.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>This tutorial was made using Xcode 11.3 and Swift 5.1. An active <a href="https://www.apple.com/apple-music/?ref=appcoda.com">Apple Music</a> subscription will be needed in order to test the app out. You may also need an active Apple Developer account in order to create some of the required identifiers and keys. You will also need to run your app on a real device because as of this time, the Simulator does not support Apple Music playback. We will also be running some Python code in order to generate private keys for us. If you don&#x2019;t have <code>pip</code> installed, don&#x2019;t worry, I will explain how to later in the tutorial.</p>



<h2 class="wp-block-heading">Creating a MusicKit Identifier</h2>



<p>The first step in communicating with the Apple Music API is to have a valid MusicKit identifier in your Apple Developer account. This identifier will be linked to our app and will let the Apple Music service know that our app is valid to access its services. Since our identifier is linked to our app&#x2019;s Bundle Identifier, let&#x2019;s quickly create the Xcode project first.</p>



<p>Open Xcode and click on <strong>Create a new Xcode Project</strong>. Under <strong>iOS</strong>, make sure that <strong>Tabbed App</strong> is the option selected before clicking on the <strong>Next</strong> button.</p>



<p>Next, name the project to <strong>MusicPlayer</strong> but feel free to change it if you like. Make sure that your <strong>User Interface&#xA0;</strong> is set to <strong>SwiftUI</strong>. Finally, take note of the <strong>Bundle Identifier</strong> as displayed below. For example, my bundle identifier is &#x201C;com.appcoda.MusicPlayer&#x201D;. But you should use your own.</p>



<p>Click on <strong>Next</strong> and choose where you would like to save your project. That&#x2019;s it! You&#x2019;ve created the project and just for reference, you should see your Bundle Identifier again on your Project Dashboard.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-1024x617.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17920" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-1024x617.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-498x300.png 498w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-1536x925.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-2048x1233.png 2048w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-1680x1012.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-1240x747.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-860x518.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-4-50x30.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Now we can create our MusicKit Identifier. Head to your <a href="developer.apple.com/account">Apple Developer account</a>. Once you login, you should be greeted with a screen that looks like this. Make sure you click on <strong>Certificates, Identifiers, &amp; Profiles</strong>.</p>



<p>Once the page loads, click on <strong>Identifiers</strong> on the left side of the page. You&#x2019;ll get a list of all the App IDs your Apple Developer account is associated with.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-1024x616.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17921" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-2048x1232.png 2048w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-6-50x30.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Now, let&#x2019;s create a new MusicKit Identifier. Click on the blue plus button next to the <strong>Identifiers</strong> title. A new page will load titled <strong>Register a New Identifier</strong>. Make sure that you select the <strong>Music IDs</strong> option before pressing <strong>Continue</strong>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-1024x616.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17922" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-2048x1232.png 2048w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-7-50x30.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Next, you&#x2019;ll be asked to quickly fill out a description and identifier for your Music ID. You can see what I filled out below. For your identifier, make sure that it is in the following format- music.&lt;YOUR-BUNDLE-ID&gt;.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-1024x616.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17923" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-2048x1232.png 2048w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-8-50x30.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Click <strong>Continue</strong> and make sure all your details are correct, click on <strong>Register</strong>.</p>



<p>That&#x2019;s it! If all worked out, you should see a list of all your Music IDs and one of them being the one you just created!</p>



<p>Next, we&#x2019;ll create a private key that is associated with the identifier we just created. This key can be used to sign a secret developer token that allows us to communicate with MusicKit.</p>



<h2 class="wp-block-heading">Creating a Private Key</h2>



<p>Generally speaking, private keys are important because they allow you to access and authenticate communication with some app services &#x2014; such as Push Notifications, MusicKit, and DeviceCheck. We&#x2019;ll need to create a private key in order to sign something called a <strong>developer token</strong>. This token will be used when sending requests to the Apple Music API in order to let them know that this request is coming from a verified developer. You&#x2019;ll use the private key to create the token in the form of a JSON web token (JWT). You can learn more about JWT <a href="https://jwt.io/introduction/?ref=appcoda.com">here</a>.</p>



<p>Still in the <strong>Certificates, Identifiers, and Profiles</strong> page, click on the <strong>Keys</strong> tab to the left side of the page. You&#x2019;ll see a list of all the keys associated with your developer account. If you&#x2019;ve ever used Push Notifications in your apps, you&#x2019;ll find the key you used for that service.</p>



<p>Let&#x2019;s create a new key for our app. Just like before, click on the plus button next to <strong>Keys</strong>. Name your key (I&#x2019;m using &#x201C;AppCoda MusicPlayer&#x201D;) and select MusicKit from the list of capabilities shown below.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="463" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-1024x463.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17924" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-1024x463.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-600x272.png 600w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-200x91.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-768x348.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-1536x695.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-1680x760.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-1240x561.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-860x389.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-680x308.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-400x181.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11-50x23.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-11.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Before you select <strong>Continue</strong>, we&#x2019;ll need to configure this capability. Click on <strong>Configure</strong> and you&#x2019;ll be shown a page where you can associate this private key with the MusicKit Identifier we created earlier. Select the Music ID you created and then click <strong>Save</strong>.</p>



<p>You&#x2019;ll go to the previous page where you can finally click on <strong>Continue</strong>. After a quick checkup to make sure everything has been entered correctly, click on <strong>Register</strong>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="343" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-1024x343.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17925" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-1024x343.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-600x201.png 600w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-200x67.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-768x257.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-1536x514.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-1680x563.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-1240x415.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-860x288.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-680x228.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-400x134.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13-50x17.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-13.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>If all goes well, you&#x2019;ll see a page like the one above asking you to download your key. Make sure you download the key and save it in a safe place as you will not be able to download your key again. Also, make sure you take note of your Key ID as we&#x2019;ll need it soon.</p>



<p>Now that we have the private key downloaded, we&#x2019;ll need to use it to create the developer token in the JWT format. However, if you look at the file you downloaded, you&#x2019;ll see that it&#x2019;s in a <code>.p8</code> file format and you probably can&#x2019;t open the file. Luckily, there&#x2019;s a way to view the private key from this file.</p>



<p>Open a new tab in your browser and head to <a href="https://filext.com/file-extension/P8?ref=appcoda.com">https://filext.com/file-extension/P8</a>. This website will read your <code>.p8</code> file and display the private key to you. Drop your file into the placeholder and wait for a couple seconds.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-1024x616.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17926" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-14.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>You can see that the private key is given to you. I&#x2019;ve hidden it from my screenshot above. You should also strive to keep this key as much of a secret since this is directly linked to your developer account. Copy the private key and save it. We&#x2019;ll also need this in a bit.</p>



<h3 class="wp-block-heading">Python Script</h3>



<p>Now it comes to the fun part, but slightly complicated. You&#x2019;ll need to create the developer token using a Python script. So, first <a href="https://github.com/appcoda/MusicKitPlayer/blob/master/musictoken.py?ref=appcoda.com">download the script file here</a>. In order for the script to work, you&#x2019;ll need to install some Python packages. MacOS already comes with Python installed, so you don&#x2019;t have to do any extra work to install Python. All you need to do is install those Python packages.</p>



<p>First, let&#x2019;s download <code>pip</code>. If you&#x2019;re not familiar with Python, <code>pip</code> is a very simple and easy-to-use package management system used to install and manage software packages written in Python. You can think of it as CocoaPods or Carthage for Python. Open <strong>Terminal</strong>. Type the following command:</p>



<pre class="wp-block-code"><code>sudo easy_install pip</code></pre>



<p>After entering your password, <code>pip</code> will be installed. If you have <code>pip</code> installed already, you&#x2019;ll probably see the following screen which means we can move to the next party.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="716" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-1024x716.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17927" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-1024x716.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-429x300.png 429w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-200x140.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-768x537.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-1240x867.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-860x601.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-680x476.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-400x280.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15-50x35.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-15.png 1364w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Now we need two packages in order for our script to work: <code>pyjwt</code> and <code>cryptography</code>. Both are used to encrypt all the sensitive information and transform it into the JWT format. Just like before enter the following two commands in terminal:</p>



<pre class="wp-block-code"><code>sudo pip install pyjwt
sudo pip install cryptography</code></pre>



<p>As long as you don&#x2019;t get any errors (usually in red text), you should be in the clear. We&#x2019;re almost done. Now we need to edit the script in order to populate it with 3 pieces of information. </p>



<ol><li>The MusicKit private key (copied from the website which displayed our <code>.p8</code> file)</li><li>The Key ID from the private key we created in the Apple Developer website</li><li>Your Apple ID Team ID</li></ol>



<p>You can find your Team ID by going to <a href="https://developer.apple.com/account?ref=appcoda.com">https://developer.apple.com/account</a> and clicking on the Membership tab to the left. </p>



<p>Now, open the script you downloaded earlier. You&#x2019;ll be able to see where to enter your own details in the script.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="616" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-1024x616.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17928" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-1024x616.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-499x300.png 499w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-1536x924.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-1680x1011.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-1240x746.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-860x517.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-19.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Some notes about modifying the script:</p>



<ul><li>Copy and paste your MusicKit private key exactly as it&#x2019;s displayed. This means there should be 4 lines in between the <strong>BEGIN PRIVATE KEY</strong> and <strong>END PRIVATE KEY</strong> (which should also be included).</li><li>In case you get confused in all the strings we&#x2019;ve seen, your Key ID is an alphanumeric 10 character string.</li></ul>



<p>When you&#x2019;re done entering all your information, save the script and head back to Terminal. Type the following command:</p>



<pre class="wp-block-code"><code>cd PATH/TO/WHERE/MUSICTOKEN.PY/IS/LOCATED</code></pre>



<p>Now, for the magic. Type the command into Terminal:</p>



<pre class="wp-block-code"><code>python musictoken.py</code></pre>



<p>If you&#x2019;ve done everything right, you&#x2019;ll see your token and a sample <code>CURL</code> request. Your Terminal screen will look like mine below.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="716" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-1024x716.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17929" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-1024x716.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-429x300.png 429w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-200x140.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-768x537.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-1240x867.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-860x601.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-680x476.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-400x280.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21-50x35.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-21.png 1364w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>If you face any errors, make sure you go back and see if you edited the script correctly. You may also want to make sure that you have the right Key ID, MusicKit private key, and Team ID. If none of these work, leave a comment below and I&#x2019;ll be happy to help.</p>



<p>If your Terminal screen looks like mine, congratulations! You&#x2019;ve successfully completed the hardest party of this tutorial. Copy your developer token and save it as we&#x2019;ll be using it in the next part of the tutorial. For the rest of the tutorial, let&#x2019;s go back to Swift and build the base layout of our app.</p>



<h2 class="wp-block-heading">Creating the UI of the Music Player app</h2>



<p>Open the Xcode project we created earlier in the tutorial. You can see that we already have our <code>Tab View</code> created for us in <code>ContentView.swift</code>. Let&#x2019;s create a new <strong>SwiftUI</strong> view for our player view. Go to <strong>File &gt; New &gt; File</strong> and make sure you have <strong>SwiftUI View</strong> selected as your preset. </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="739" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-1024x739.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17930" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-1024x739.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-416x300.png 416w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-200x144.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-768x554.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-1240x895.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-860x621.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-680x491.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-400x289.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22-50x36.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-22.png 1445w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Save this file as <code>PlayerView.swift</code>. And, you should see the very basic <strong>SwiftUI</strong> View.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-1024x617.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17931" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-1024x617.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-498x300.png 498w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-1536x925.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-1680x1012.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-1240x747.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-860x518.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-23.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Let&#x2019;s change this up. Command-click on the <code>Text</code> view and choose <strong>Embed in VStack</strong>. This will be the view that displays our song&#x2019;s title. Let&#x2019;s add another <code>Text</code> view inside the <strong>VStack</strong>. This can be the view that displays the artist&#x2019;s name. Change the values of both <code>Text</code> structs to reflect the change.</p>



<pre class="wp-block-code"><code>VStack {
    Text(&quot;Song Title&quot;)
    Text(&quot;Artist Name&quot;)
}</code></pre>



<p>In order to offer a clearer distinction between both <code>Text</code> views, I&#x2019;ll change the font and add some spacing between both views. This is for a purely design-based purpose. You can modify these values to whatever you see fit. Here is the code:</p>



<pre class="wp-block-code"><code>VStack(spacing: 8) {
    Text(&quot;Song Title&quot;)
        .font(Font.system(.title).bold())
    Text(&quot;Artist Name&quot;)
        .font(.system(.headline))
}</code></pre>



<p>That&#x2019;s much better! The users of our app can clearly distinguish between our song&#x2019;s title and its artist. Now let&#x2019;s add an <code>Image</code> view so we can show the album cover to our users! Before we do that, let&#x2019;s copy all the code we have so far and paste it into a <code>GeometryReader</code>. This is a container view that defines its content as a function of its own size and coordinate space. It helps with resizing views for different device sizes.</p>



<p>Click on the Plus button in the top right corner of Xcode and search for <code>Geometry Reader</code>. </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="590" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-1024x590.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17932" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-1024x590.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-521x300.png 521w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-200x115.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-768x442.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-1536x885.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-1680x968.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-1240x714.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-860x495.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-680x392.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-400x230.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26-50x29.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-26.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Select this and drag it to paste the code about where we declare our <code>VStack</code>. Now copy the <code>VStack</code> struct and paste it inside the <code>GeometryReader</code>&#x2019;s placeholder. While our preview will still look the same, our code should now look like this.</p>



<pre class="wp-block-code"><code>GeometryReader { geometry in
    VStack(spacing: 8) {
        Text(&quot;Song Title&quot;)
            .font(Font.system(.title).bold())
        Text(&quot;Artist Name&quot;)
            .font(.system(.headline))
    }
}</code></pre>



<p>Now we can add an <code>Image</code> view that will function as a place where we can display the album cover. Modify your code to look like this.</p>



<pre class="wp-block-code"><code>GeometryReader { geometry in
    // 1
    VStack(spacing: 24) {
        // 2
        Image(systemName: &quot;a.square&quot;)
            .resizable() // 3
            .frame(width: geometry.size.width - 24, height: geometry.size.width - 24) // 4
            .cornerRadius(20)
            .shadow(radius: 10)

        VStack(spacing: 8) {
            Text(&quot;Song Title&quot;)
                .font(Font.system(.title).bold())
            Text(&quot;Artist Name&quot;)
                .font(.system(.headline))
        }
    }
}</code></pre>



<ol><li>First, I take the existing <code>VStack</code> and wrap it inside another <code>VStack</code>. This offers some spacing in between the <code>Image</code> view and the <code>Text</code> views.</li><li>Next, I created the <code>Image</code> view. Since the app has no data right now, I&#x2019;m using an <strong>SF Symbol</strong> as a placeholder image.</li><li>In order to resize the <code>Image</code>, it&#x2019;s important to add the <code>.resizable()</code> function.</li><li>Finally, I define the frame of my <code>Image</code> view. <code>geometry.size.width</code> is the width of the device. You can think of it like a <strong>SwiftUI</strong> version of <code>self.view.frame.size.width</code>. I also subtract 24 in order to create some margins.</li></ol>



<p>Your preview should look a little like this now.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-1024x617.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17933" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-1024x617.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-498x300.png 498w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-1536x925.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-1680x1012.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-1240x747.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-860x518.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-27.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Now we need to create our play, rewind, and skip buttons. Click on the plus button like before and drag a button right below the <code>VStack</code> where we define our song&#x2019;s information.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-1024x617.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17934" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-1024x617.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-498x300.png 498w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-1536x925.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-1680x1012.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-1240x747.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-860x518.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-28.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Let&#x2019;s modify this button so it functions as our rewind button. Change the <code>Button</code> view code to look like this.</p>



<pre class="wp-block-code"><code>Button(action: {
    // 1
    print(&quot;Rewind&quot;)
}) {
    // 2
    ZStack {
        // 3
        Circle()
            .frame(width: 80, height: 80)
            .accentColor(.pink)
            .shadow(radius: 10)
        Image(systemName: &quot;backward.fill&quot;)
            .foregroundColor(.white)
            .font(.system(.title))
    }
}</code></pre>



<ol><li>Currently since we don&#x2019;t have access to the <code>MediaPlayer</code> framework, we&#x2019;ll just print a statement when the button is tapped.</li><li>Next we define the look of our button. I decided to use a <code>ZStack</code> so we can use an <strong>SF Symbol</strong> as an image and use the <code>Circle</code> view as its background.</li><li>I create the <code>Circle</code> view first and give it its frame, color, and shadow for design purposes. I then use an <strong>SF Symbol</strong> to provide an image for the button.</li></ol>



<p>We need two more of these buttons next to each other. Command and click on the <code>Button</code> view and click on <strong>Embed in HStack</strong>. Copy the button code and paste it inside the <code>HStack</code> struct two more times.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-1024x617.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17936" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-1024x617.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-498x300.png 498w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-1536x925.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-1680x1012.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-1240x747.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-860x518.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-30.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Obviously we don&#x2019;t want our player to look like this so let&#x2019;s modify the <code>HStack</code> code.</p>



<pre class="wp-block-code"><code>HStack(spacing: 40) {
    Button(action: {
        print(&quot;Rewind&quot;)
    }) {
        ZStack {
            Circle()
                .frame(width: 80, height: 80)
                .accentColor(.pink)
                .shadow(radius: 10)
            Image(systemName: &quot;backward.fill&quot;)
                .foregroundColor(.white)
                .font(.system(.title))
        }
    }

    Button(action: {
        print(&quot;Pause&quot;)
    }) {
        ZStack {
            Circle()
                .frame(width: 80, height: 80)
                .accentColor(.pink)
                .shadow(radius: 10)
            Image(systemName: &quot;pause.fill&quot;)
                .foregroundColor(.white)
                .font(.system(.title))
        }
    }

    Button(action: {
        print(&quot;Skip&quot;)
    }) {
        ZStack {
            Circle()
                .frame(width: 80, height: 80)
                .accentColor(.pink)
                .shadow(radius: 10)
            Image(systemName: &quot;forward.fill&quot;)
                .foregroundColor(.white)
                .font(.system(.title))
        }
    }
}</code></pre>



<p>In the code above, I&#x2019;m simply adding a spacing of 40 between my buttons. All of them are similar to the button&#x2019;s I&#x2019;ve created earlier. The only difference is that each button prints a different statement regarding its function and has a different image. </p>



<p>Your player view should look like this now:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-1024x617.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17937" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-1024x617.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-498x300.png 498w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-1536x925.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-1680x1012.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-1240x747.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-860x518.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-31.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Next, let&#x2019;s build the Search View.</p>



<h3 class="wp-block-heading">Search View</h3>



<p>Just like before, create a new <strong>SwiftUI</strong> view and name this file <code>SearchView.swift</code>.  You&#x2019;ll be greeted with the familiar template view.</p>



<p>Our search view will be very simple. It just needs a <code>TextField</code> view for searching songs and a <code>List</code> view for displaying the results. Meanwhile, we also need to populate some fake data since the app hasn&#x2019;t connected with the Apple Music API. At the top of the file, right before you declare <code>body</code>, type the following:</p>



<pre class="wp-block-code"><code>@State private var searchText = &quot;&quot;
let songs = [&quot;Blinding Lights&quot;, &quot;That Way&quot;, &quot;This Is Me&quot;]

var body: some View {
    Text(&quot;Hello, World!&quot;)
}</code></pre>



<p>The <code>searchText</code> variable is the binding variable we&#x2019;ll use to connect our <code>TextField</code> view with. We define the <code>songs</code> array to populate our list with some temporary data.</p>



<p>Let&#x2019;s build the <code>TextField</code> view first. Remove the <code>Text</code> view and replace it with the following code:</p>



<pre class="wp-block-code"><code>VStack {
    TextField(&quot;Search Songs&quot;, text: $searchText, onCommit: {
        print(self.searchText)
    })
    .textFieldStyle(RoundedBorderTextFieldStyle())
    .padding(.horizontal, 16)
    .accentColor(.pink)
}</code></pre>



<p>I&#x2019;ve created the <code>TextField</code> view with a placeholder text of &#x201C;Search Songs&#x201D; and attached any text type into this View to the <code>searchText</code> variable.  The <code>onCommit</code> method is called when the user pressed <strong>Return</strong> on their keyboard. In the next part of the tutorial, we&#x2019;ll implement our search functionality within this method.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-1024x617.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17938" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-1024x617.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-498x300.png 498w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-1536x925.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-1680x1012.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-1240x747.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-860x518.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-33.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Next, I&#x2019;ll create the <code>List</code> view and populate it with the data from above. Underneath the <code>TextField</code>, paste the following code.</p>



<pre class="wp-block-code"><code>List {
    // 1
    ForEach(songs, id:\.self) { songTitle in
        // 2
        HStack {
            // 3
            Image(systemName: &quot;rectangle.stack.fill&quot;)
                .resizable()
                .frame(width: 40, height: 40)
                .cornerRadius(5)
                .shadow(radius: 2)

            // 4
            VStack(alignment: .leading) {
                Text(songTitle)
                    .font(.headline)
                Text(&quot;Artist Name&quot;)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
            Spacer()
            // 5
            Button(action: {
                print(&quot;Playing \(songTitle)&quot;)
            }) {
                Image(systemName: &quot;play.fill&quot;)
                    .foregroundColor(.pink)
            }
        }
    }
}
.accentColor(.pink)</code></pre>



<p>If you&#x2019;ve worked with the <code>List</code> view or the <code>ForEach</code> structure before, this should look familiar. If not, I&#x2019;ll walk you through the code.</p>



<ol><li>Inside my <code>List</code> view, I initialize the <code>ForEach</code> structure. This makes it easy to create multiple copies of views that I won&#x2019;t have to explicitly code. As my data, I pass the <code>songs</code> array we created earlier. I also pass  each element in that array as a variable called <code>songTitle</code>. This is so we can easily populate our cells without having to worry about array indexes. </li><li>Next, to emulate the look of a <code>UITableViewCell</code>, I create an <code>HStack</code>. I&#x2019;ll be placing the album cover, song title, song artist, and add button within each cell inside the <code>HStack</code>.</li><li>Next is the <code>Image</code> view. As before, I&#x2019;m using an <strong>SF Symbol</strong> as a placeholder image. </li><li>Next comes our <code>Text</code> views. I place them inside a <code>VStack</code> to conserve space and display multiple <code>Text</code> views in the same place. You&#x2019;ll notice that the string value of our first <code>Text</code> view is the <code>songTitle</code> variable we created earlier.</li><li>Finally, I add a <code>Play</code> button which indicates to the user that our music player will play this song. Currently, it only prints to the console. In the next part of the tutorial, we&#x2019;ll manage adding songs to the queue inside this method.</li></ol>



<p>That&#x2019;s all! Take a look at your Canvas and make sure it looks something like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-1024x617.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17939" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-1024x617.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-498x300.png 498w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-1536x925.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-1680x1012.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-1240x747.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-860x518.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-34.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h3 class="wp-block-heading">Putting it all together</h3>



<p>We&#x2019;re almost done! All that&#x2019;s left is going back to <code>ContentView.swift</code> and modifying the inside of our <code>TabView</code> to make sure it displays the two views we have created. Delete all the code inside <code>TabView</code> and replace it with the following.</p>



<pre class="wp-block-code"><code>TabView(selection: $selection) {
    PlayerView()
        .tag(0)
        .tabItem {
            VStack {
                Image(systemName: &quot;music.note&quot;)
                Text(&quot;Player&quot;)
            }
        }
    SearchView()
        .tag(1)
        .tabItem {
            VStack {
                Image(systemName: &quot;magnifyingglass&quot;)
                Text(&quot;Search&quot;)
            }
        }
}
.accentColor(.pink)</code></pre>



<p>In the above code, I&#x2019;m calling both <code>PlayerView()</code> and <code>SearchView()</code> as the two views in our <code>TabView</code>. As such, we&#x2019;ll only have two tabs. I&#x2019;ve also created the look of those tabs with a simple <code>Image</code> and <code>Text</code>. </p>



<p>By now you must have noticed that I&#x2019;ve been using <code>Color.pink</code> inside all my buttons and <code>.accentColors</code>. This provides the app with a unique, music-themed design. You&#x2019;re free to change the colors, fonts, and shapes to however you wish. </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-1024x617.png" alt="Introduction to MusicKit: Building a Music Player in SwiftUI" class="wp-image-17940" srcset="https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-1024x617.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-498x300.png 498w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-768x462.png 768w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-1536x925.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-1680x1012.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-1240x747.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-860x518.png 860w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-680x409.png 680w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-400x241.png 400w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2020/04/musickit-player-35.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading">What&#x2019;s Next</h2>



<p>Congratulations! You&#x2019;ve done a lot in this tutorial by venturing out of Swift and into further technologies like Python, Web Token, Encryption, and API handling. This was a lot but if you&#x2019;ve made it to the end, congrats! The hardest part about using MusicKit is generating your keys and developer tokens. You can download the final project <a href="https://github.com/appcoda/MusicKitPlayer/releases/tag/0.5?ref=appcoda.com" class="rank-math-link">here</a>.</p>



<p>In the next part of this tutorial series, we&#x2019;ll complete our app. I&#x2019;ll show you how to access the Apple Music API and make web requests to the API. Furthermore, I&#x2019;ll teach you how to use <code>MediaPlayer</code> to play music and control playback from your device. If you have any doubts, feel free to leave a comment. Stay tuned!</p>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[Working with JSON and Codable in Swift 5]]></title><description><![CDATA[<!--kg-card-begin: html-->
<p>First, what&#x2019;s JSON? JSON (short for JavaScript Object Notation) is a text-based, lightweight, and easy way for storing and exchanging data. It&#x2019;s commonly used for representing structural data and data interchange in client-server applications, serving as an alternative to XML. A lot of the web services</p>]]></description><link>https://www.appcoda.com/json-codable-swift/</link><guid isPermaLink="false">66612a0f166d3c03cf0114bd</guid><category><![CDATA[iOS Programming]]></category><category><![CDATA[Swift]]></category><dc:creator><![CDATA[Simon Ng]]></dc:creator><pubDate>Wed, 05 Feb 2020 18:33:01 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2020/02/json-0.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html-->
<img src="https://www.appcoda.com/content/images/wordpress/2020/02/json-0.png" alt="Working with JSON and Codable in Swift 5"><p>First, what&#x2019;s JSON? JSON (short for JavaScript Object Notation) is a text-based, lightweight, and easy way for storing and exchanging data. It&#x2019;s commonly used for representing structural data and data interchange in client-server applications, serving as an alternative to XML. A lot of the web services we use every day have JSON-based APIs. Most of the iOS apps, including Twitter, Facebook, and Flickr send data to their backend web services in JSON format.</p>



<p><div class="alert gray"><strong>Editor&#x2019;s note</strong>: This is a <a href="https://www.appcoda.com/intermediate-swift-tips/">sample chapter</a> of the <a href="https://www.appcoda.com/intermediate-swift-programming-book/">Intermediate iOS 13 Programming with Swift</a> book.</div></p>



<p>As an example, here is a JSON representation of a sample Movie object:</p>



<pre class="wp-block-code"><code>{
    &quot;title&quot;: &quot;The Amazing Spider-man&quot;,
    &quot;release_date&quot;: &quot;03/07/2012&quot;,
    &quot;director&quot;: &quot;Marc Webb&quot;,
    &quot;cast&quot;: [
        {
            &quot;name&quot;: &quot;Andrew Garfield&quot;,
            &quot;character&quot;: &quot;Peter Parker&quot;
        },
        {
            &quot;name&quot;: &quot;Emma Stone&quot;,
            &quot;character&quot;: &quot;Gwen Stacy&quot;
        },
        {
            &quot;name&quot;: &quot;Rhys Ifans&quot;,
            &quot;character&quot;: &quot;Dr. Curt Connors&quot;
        }
    ]
}</code></pre>



<p>As you can see, JSON formatted data is more human-readable and easier to parse than XML. I&#x2019;ll not go into the details of JSON. This is not the purpose of this chapter. If you want to learn more about the technology, I recommend you to check out the JSON Guide at <a href="http://www.json.org/?ref=appcoda.com">http://www.json.org/</a>.</p>



<p>Since the release of iOS 5, the iOS SDK has already made it easy for developers to fetch and parse JSON data. It comes with a handy class called <code>NSJSONSerialization</code>, which can automatically convert JSON formatted data to objects. Later in this chapter, I will show you how to use the API to parse some sample JSON formatted data, returned by a web service. Once you understand how it works, it is fairly easy to build an app by integrating with other free/paid web services.</p>



<p>Since the release of Swift 4, Apple introduced the <code>Codable</code> protocol to simplify the whole JSON archival and serialization process. We will also look into this new feature and see how we can apply it in JSON parsing.</p>



<h2 class="wp-block-heading">JSON Demo App</h2>



<p>As usual, we&#x2019;ll create a demo app. Let&#x2019;s call it <em>KivaLoan</em>. The reason why we name the app <em>KivaLoan</em> is that we will utilize a JSON-based API provided by <a href="http://kiva.org/?ref=appcoda.com">Kiva.org</a>. If you haven&#x2019;t heard of Kiva, it is a non-profit organization with a mission to connect people through lending to alleviate poverty. It lets individuals lend as little as $25 to help create opportunities around the world. Kiva provides free web-based APIs for developers to access their data. For our demo app, we&#x2019;ll call up the following Kiva API to retrieve the most recent fundraising loans and display them in a table view:</p>



<pre class="wp-block-code"><code>https://api.kivaws.org/v1/loans/newest.json</code></pre>



<p> <div class="alert gray"><strong>Quick note</strong>: Starting from iOS 9, Apple introduced a feature called App Transport Security (ATS) with the aim to improve the security of connections between an app and web services. By default, all outgoing connections should ride on HTTPS. Otherwise, your app will not be allowed to connect to the web service. Optionally, you can add a key named NSAllowsArbitraryLoads in the Info.plist and set the value to YES to disable ATS, so that you can connect to web APIs over HTTP. <br><br>However, you&#x2019;ll have to take note if you use NSAllowsArbitraryLoads in your apps. In iOS 10, Apple further enforces ATS for all iOS apps. By January 2017, all iOS apps should be ATS-compliant. In other words, if your app connects to external any web services, the connection must be over HTTPS. If your app can&#x2019;t fulfil this requirement, Apple will not allow it to be released on the App Store.</div></p>



<p>The returned data of the above API is in JSON format. Here is a sample result:</p>



<pre class="wp-block-code"><code>loans: (
        {
        activity = Retail;
        &quot;basket_amount&quot; = 0;
        &quot;bonus_credit_eligibility&quot; = 0;
        &quot;borrower_count&quot; = 1;
        description =         {
            languages =             (
                fr,
                en
            );
        };
        &quot;funded_amount&quot; = 0;
        id = 734117;
        image =         {
            id = 1641389;
            &quot;template_id&quot; = 1;
        };
        &quot;lender_count&quot; = 0;
        &quot;loan_amount&quot; = 750;
        location =         {
            country = Senegal;
            &quot;country_code&quot; = SN;
            geo =             {
                level = country;
                pairs = &quot;14 -14&quot;;
                type = point;
            };
        };
        name = &quot;Mar\U00e8me&quot;;
        &quot;partner_id&quot; = 108;
        &quot;planned_expiration_date&quot; = &quot;2016-08-05T09:20:02Z&quot;;
        &quot;posted_date&quot; = &quot;2016-07-06T09:20:02Z&quot;;
        sector = Retail;
        status = fundraising;
        use = &quot;to buy fabric to resell&quot;;
    },
....
....
)</code></pre>



<p>You will learn how to use the <code>NSJSONSerialization</code> class to convert the JSON formatted data into objects. It&#x2019;s unbelievably simple. You&#x2019;ll see what I mean in a while.</p>



<p>To keep you focused on learning the JSON implementation, you can first download the project template from <a href="http://www.appcoda.com/resources/swift5/KivaLoanStarter.zip">http://www.appcoda.com/resources/swift5/KivaLoanStarter.zip</a>. I have already created the skeleton of the app for you. It is a simple table-based app that displays a list of loans provided by Kiva.org. The project template includes a pre-built storyboard and custom classes for the table view controller and prototype cell. If you run the template, it should result in an empty table app.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="430" src="https://www.appcoda.com/content/images/wordpress/2020/02/json-1-1024x430.png" alt="Working with JSON and Codable in Swift 5" class="wp-image-17723" srcset="https://www.appcoda.com/content/images/wordpress/2020/02/json-1-1024x430.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-600x252.png 600w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-200x84.png 200w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-768x323.png 768w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-1536x646.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-1680x706.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-1240x521.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-860x361.png 860w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-680x286.png 680w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-400x168.png 400w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1-50x21.png 50w, https://www.appcoda.com/content/images/wordpress/2020/02/json-1.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading">Creating JSON Data Model</h2>



<p>We will first create a class to model a loan. It&#x2019;s not required for loading JSON but the best practice is to create a separate class (or structure) for storing the data model. The <code>Loan</code> class represents the loan information in the KivaLoan app and is used to store the loan information returned by Kiva.org. To keep things simple, we won&#x2019;t use all the returned data of a loan. Instead, the app will just display the following fields of a loan:</p>



<ul><li>Name of the loan applicant </li></ul>



<pre class="wp-block-code"><code>name = &quot;Mar\U00e8me&quot;;</code></pre>



<ul><li>Country of the loan applicant </li></ul>



<pre class="wp-block-code"><code>location =         {
            country = Senegal;
            &quot;country_code&quot; = SN;
            geo =             {
                level = country;
                pairs = &quot;14 -14&quot;;
                type = point;
            };
        };</code></pre>



<ul><li>How the loan will be used</li></ul>



<pre class="wp-block-code"><code>use = &quot;to buy fabric to resell&quot;;</code></pre>



<ul><li>Amount</li></ul>



<pre class="wp-block-code"><code>&quot;loan_amount&quot; = 750;</code></pre>



<p>These fields are good enough for filling up the labels in the table view. Now create a new class file using the Swift File template. Name it <code>Loan.swift</code> and declare the <code>Loan</code> structure like this:</p>



<pre class="wp-block-code"><code>struct Loan {

    var name: String = &quot;&quot;
    var country: String = &quot;&quot;
    var use: String = &quot;&quot;
    var amount: Int = 0

}</code></pre>



<p>JSON supports a few basic data types including number, String, Boolean, Array, and Objects (an associated array with key and value pairs).</p>



<p>For the loan fields, the loan amount is stored as a numeric value in the JSON-formatted data. This is why we declared the <code>amount</code> property with the type  <code>Int</code>. For the rest of the fields, they are declared with the type <code>String</code>. </p>



<h2 class="wp-block-heading">Fetching Loans with the Kiva API</h2>



<p>As I mentioned earlier, the Kiva API is free to use. No registration is required. You may point your browser to the following URL and you&#x2019;ll get the latest fundraising loans in JSON format.</p>



<pre class="wp-block-code"><code>https://api.kivaws.org/v1/loans/newest.json</code></pre>



<p>Okay, let&#x2019;s see how we can call up the Kiva API and parse the returned data. First, open <code>KivaLoanTableViewController.swift</code> and declare two variables at the very beginning:</p>



<pre class="wp-block-code"><code>private let kivaLoanURL = &quot;https://api.kivaws.org/v1/loans/newest.json&quot;
private var loans = [Loan]()</code></pre>



<p>We just defined the URL of the Kiva API, and declare the <code>loans</code> variable for storing an array of Loan objects. Next, insert the following methods in the same file:</p>



<pre class="wp-block-code"><code>func getLatestLoans() {
    guard let loanUrl = URL(string: kivaLoanURL) else {
        return
    }

    let request = URLRequest(url: loanUrl)
    let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) -&gt; Void in

        if let error = error {
            print(error)
            return
        }

        // Parse JSON data
        if let data = data {
            self.loans = self.parseJsonData(data: data)

            // Reload table view
            OperationQueue.main.addOperation({ 
                self.tableView.reloadData()
            })
        }
    })

    task.resume()
}

func parseJsonData(data: Data) -&gt; [Loan] {

    var loans = [Loan]()

    do {
        let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary

        // Parse JSON data
        let jsonLoans = jsonResult?[&quot;loans&quot;] as! [AnyObject]
        for jsonLoan in jsonLoans {
            let loan = Loan()
            loan.name = jsonLoan[&quot;name&quot;] as! String
            loan.amount = jsonLoan[&quot;loan_amount&quot;] as! Int
            loan.use = jsonLoan[&quot;use&quot;] as! String
            let location = jsonLoan[&quot;location&quot;] as! [String:AnyObject]
            loan.country = location[&quot;country&quot;] as! String
            loans.append(loan)
        }

    } catch {
        print(error)
    }

    return loans
}</code></pre>



<p>These two methods form the core part of the app. Both methods work collaboratively to call the Kiva API, retrieve the latest loans in JSON format and translate the JSON-formatted data into an array of <code>Loan</code> objects. Let&#x2019;s go through them in detail.</p>



<p>In the <code>getLatestLoans</code> method, we first instantiate the <code>URL</code> structure with the URL of the Kiva Loan API. The initialization returns us an optional. This is why we use the <code>guard</code> keyword to see if the optional has a value. If not, we simply return and skip all the code in the method.</p>



<p>Next, we create a <code>URLSession</code> with the load URL. The <code>URLSession</code> class provides APIs for dealing with online content over HTTP and HTTPS. The shared session is good enough for making simple HTTP/HTTPS requests. In case you have to support your own networking protocol, <code>URLSession</code> also provides you an option to create a custom session.</p>



<p>One great thing of <code>URLSession</code> is that you can add a series of session tasks to handle the loading of data, as well as uploading and downloading files and data fetching from servers (e.g. JSON data fetching). </p>



<p>With sessions, you can schedule three types of tasks: <em>data tasks</em> (<code>URLSessionDataTask</code>) for retrieving data to memory, <em>download tasks</em> (<code>URLSessionDownloadTask</code>) for downloading a file to disk, and <em>upload tasks</em> (<code>URLSessionUploadTask</code>) for uploading a file from disk. Here we use the data task to retrieve contents from Kiva.org. To add a data task to the session, we call the <code>dataTask</code> method with the specific URL request. After you add the task, the session will not take any action. You have to call the resume method (i.e. <code>task.resume()</code>) to initiate the data task.</p>



<p>Like most networking APIs, the <code>URLSession</code> API is asynchronous. Once the request completes, it returns the data (as well as errors) by calling the completion handler.</p>



<p>In the completion handler, immediately after the data is returned, we check for an error. If no error is found, we invoke the <code>parseJsonData</code> method. </p>



<p>The data returned is in JSON format. We create a helper method called <code>parseJsonData</code> for converting the given JSON-formatted data into an array of <code>Loan</code> objects. The Foundation framework provides the <code>JSONSerialization</code> class, which is capable of converting JSON to Foundation objects and converting Foundation objects to JSON. In the code snippet, we call the <code>jsonObject</code> method with the given JSON data to perform the conversion. </p>



<p>When converting JSON formatted data to objects, the top-level item is usually converted to a Dictionary or an Array. In this case, the top level of the returned data of the Kiva API is converted to a dictionary. You can access the array of loans using the key <code>loans</code>. </p>



<p>How do you know what key to use? </p>



<p>You can either refer to the API documentation or test the JSON data using a JSON browser (e.g. http://jsonviewer.stack.hu). If you&#x2019;ve loaded the Kiva API into the JSON browser, here is an excerpt from the result:</p>



<pre class="wp-block-code"><code>{
  &quot;paging&quot;: {
    &quot;page&quot;: 1,
    &quot;total&quot;: 5297,
    &quot;page_size&quot;: 20,
    &quot;pages&quot;: 265
  },
  &quot;loans&quot;: [
    {
      &quot;id&quot;: 794429,
      &quot;name&quot;: &quot;Joel&quot;,
      &quot;description&quot;: {
        &quot;languages&quot;: [
          &quot;es&quot;,
          &quot;en&quot;
        ]
      },
      &quot;status&quot;: &quot;fundraising&quot;,
      &quot;funded_amount&quot;: 0,
      &quot;basket_amount&quot;: 0,
      &quot;image&quot;: {
        &quot;id&quot;: 1729143,
        &quot;template_id&quot;: 1
      },
      &quot;activity&quot;: &quot;Home Appliances&quot;,
      &quot;sector&quot;: &quot;Personal Use&quot;,
      &quot;use&quot;: &quot;To buy home appliances.&quot;,
      &quot;location&quot;: {
        &quot;country_code&quot;: &quot;PE&quot;,
        &quot;country&quot;: &quot;Peru&quot;,
        &quot;town&quot;: &quot;Ica&quot;,
        &quot;geo&quot;: {
          &quot;level&quot;: &quot;country&quot;,
          &quot;pairs&quot;: &quot;-10 -76&quot;,
          &quot;type&quot;: &quot;point&quot;
        }
      },
      &quot;partner_id&quot;: 139,
      &quot;posted_date&quot;: &quot;2015-11-20T08:50:02Z&quot;,
      &quot;planned_expiration_date&quot;: &quot;2016-01-04T08:50:02Z&quot;,
      &quot;loan_amount&quot;: 400,
      &quot;borrower_count&quot;: 1,
      &quot;lender_count&quot;: 0,
      &quot;bonus_credit_eligibility&quot;: true,
      &quot;tags&quot;: [

      ]
    },
    {
      &quot;id&quot;: 797222,
      &quot;name&quot;: &quot;Lucy&quot;,
      &quot;description&quot;: {
        &quot;languages&quot;: [
          &quot;en&quot;
        ]
      },
      &quot;status&quot;: &quot;fundraising&quot;,
      &quot;funded_amount&quot;: 0,
      &quot;basket_amount&quot;: 0,
      &quot;image&quot;: {
        &quot;id&quot;: 1732818,
        &quot;template_id&quot;: 1
      },
      &quot;activity&quot;: &quot;Farm Supplies&quot;,
      &quot;sector&quot;: &quot;Agriculture&quot;,
      &quot;use&quot;: &quot;To purchase a biogas system for clean cooking&quot;,
      &quot;location&quot;: {
        &quot;country_code&quot;: &quot;KE&quot;,
        &quot;country&quot;: &quot;Kenya&quot;,
        &quot;town&quot;: &quot;Gatitu&quot;,
        &quot;geo&quot;: {
          &quot;level&quot;: &quot;country&quot;,
          &quot;pairs&quot;: &quot;1 38&quot;,
          &quot;type&quot;: &quot;point&quot;
        }
      },
      &quot;partner_id&quot;: 436,
      &quot;posted_date&quot;: &quot;2016-11-20T08:50:02Z&quot;,
      &quot;planned_expiration_date&quot;: &quot;2016-01-04T08:50:02Z&quot;,
      &quot;loan_amount&quot;: 800,
      &quot;borrower_count&quot;: 1,
      &quot;lender_count&quot;: 0,
      &quot;bonus_credit_eligibility&quot;: false,
      &quot;tags&quot;: [

      ]
    },

     ...</code></pre>



<p>As you can see from the above code, <code>paging</code> and <code>loans</code> are two of the top-level items. Once the <code>JSONSerialization</code> class converts the JSON data, the result (i.e. <code>jsonResult</code>) is returned as a Dictionary with the top-level items as keys. This is why we can use the key <code>loans</code> to access the array of loans. Here is the line of code for your reference:</p>



<pre class="wp-block-code"><code>let jsonLoans = jsonResult?[&quot;loans&quot;] as! [AnyObject]</code></pre>



<p>With the array of loans (i.e. jsonLoans) returned, we loop through the array. Each of the array items (i.e. jsonLoan) is converted into a dictionary. In the loop, we extract the loan data from each of the dictionaries and save them in a <code>Loan</code> object. Again, you can find the keys (highlighted in yellow) by studying the JSON result. The value of a particular result is stored as <code>AnyObject</code>. <code>AnyObject</code> is used because a JSON value could be a String, Double, Boolean, Array, Dictionary or null. This is why you have to downcast the value to a specific type such as <code>String</code> and <code>Int</code>. Lastly, we put the <code>loan</code> object into the <code>loans</code> array, which is the return value of the method.</p>



<pre class="wp-block-code"><code>for jsonLoan in jsonLoans {
    var loan = Loan()

    loan.name = jsonLoan[&quot;name&quot;] as! String
    loan.amount = jsonLoan[&quot;loan_amount&quot;] as! Int
    loan.use = jsonLoan[&quot;use&quot;] as! String
    let location = jsonLoan[&quot;location&quot;] as! [String: AnyObject]
    loan.country = location[&quot;country&quot;] as! String

    loans.append(loan)
}</code></pre>



<p>After the JSON data is parsed and the array of loans is returned, we call the <code>reloadData</code> method to reload the table. You may wonder why we need to call <code>OperationQueue.main.addOperation</code> and execute the data reload in the main thread. </p>



<p>The block of code in the completion handler of the data task is executed in a background thread. If you call the <code>reloadData</code> method in the background thread, the data reload will not happen immediately. To ensure a responsive GUI update, this operation should be performed in the main thread. This is why we call the <code>OperationQueue.main.addOperation</code> method and request to run the <code>reloadData</code> method in the main queue.</p>



<pre class="wp-block-code"><code>OperationQueue.main.addOperation({ 
    self.tableView.reloadData()
})</code></pre>



<p><strong>Quick note:</strong> You can also use <code>dispatch_async</code> function to execute a block of code in the main thread. But according to Apple, it is recommended to use <code>OperationQueue</code> over <code>dispatch_async</code>. As a general rule, Apple recommends using the highest-level APIs rather than dropping down to the low-level ones.</p>



<h2 class="wp-block-heading">Displaying Loans in A Table View</h2>



<p>With the <code>loans</code> array in place, the last thing we need to do is to display the data in the table view. Update the following methods in  <code>KivaLoanTableViewController.swift</code>:</p>



<pre class="wp-block-code"><code>override func numberOfSections(in tableView: UITableView) -&gt; Int {
    // Return the number of sections
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
    // Return the number of rows
    return loans.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: &quot;Cell&quot;, for: indexPath) as! KivaLoanTableViewCell

    // Configure the cell...
    cell.nameLabel.text = loans[indexPath.row].name
    cell.countryLabel.text = loans[indexPath.row].country
    cell.useLabel.text = loans[indexPath.row].use
    cell.amountLabel.text = &quot;$\(loans[indexPath.row].amount)&quot;

    return cell
}</code></pre>



<p>The above code is pretty straightforward if you are familiar with the implementation of <code>UITableView</code>. In the <code>tableView(_:cellForRowAt:)</code> method, we retrieve the loan information from the <code>loans</code> array and populate them in the custom table cell. One thing to take note of is the code below:</p>



<pre class="wp-block-code"><code>&quot;$\(loans[indexPath.row].amount)&quot;</code></pre>



<p>In some cases, you may want to create a string by adding both string (e.g. $) and integer (e.g. <code>loans[indexPath.row].amount</code>) together. Swift provides a powerful way to create these kinds of strings, known as string interpolation. You can make use of it by using the above syntax.</p>



<p>Lastly, insert the following line of code in the <code>viewDidLoad</code> method to start fetching the loan data:</p>



<pre class="wp-block-code"><code>getLatestLoans()</code></pre>



<h2 class="wp-block-heading">Compile and Run the App</h2>



<p>Now it&#x2019;s time to test the app. Compile and run it in the simulator. Once launched, the app will pull the latest loans from Kiva.org and display them in the table view.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="682" src="https://www.appcoda.com/content/images/wordpress/2020/02/json-2-1024x682.png" alt="Working with JSON and Codable in Swift 5" class="wp-image-17724" srcset="https://www.appcoda.com/content/images/wordpress/2020/02/json-2-1024x682.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-451x300.png 451w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-200x133.png 200w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-768x511.png 768w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-1536x1022.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-1680x1118.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-1240x825.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-860x572.png 860w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-680x453.png 680w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-400x266.png 400w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2-50x33.png 50w, https://www.appcoda.com/content/images/wordpress/2020/02/json-2.png 1998w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>For reference, you can download the complete Xcode project from <a href="http://www.appcoda.com/resources/swift5/KivaLoan.zip">http://www.appcoda.com/resources/swift5/KivaLoan.zip</a>.</p>



<h2 class="wp-block-heading">Introducing Codable</h2>



<p>Since the release of Swift 4, Apple introduced a new way to encode and decode JSON data using <code>Codable</code>. We will rewrite the JSON decoding part of the demo app using this new approach.</p>



<p>Before we jump right into the modification, let me give you a basic walkthrough of <code>Codable</code>. If you look into the documentation of <code>Codable</code>, it is just a type alias of a protocol composition:</p>



<pre class="wp-block-code"><code>typealias Codable = Decodable &amp; Encodable</code></pre>



<p><code>Decodable</code> and <code>Encodable</code> are the two actual protocols you need to work with. However, for convenience&#x2019;s sake, we usually refer to this type alias for handling JSON encoding and decoding.</p>



<p>First, what&#x2019;s the advantage of using <code>Codable</code> over the traditional approach for encoding/decoding JSON? If you go back to the previous section and read the code again, you will notice that we had to manually parse the JSON data, convert it into dictionaries and create the <code>Loan</code> objects.</p>



<p><code>Codable</code> simplifies the whole process by offering developers a different way to decode (or encode) JSON. As long as your type conforms to the <code>Codable</code> protocol, together with the new <code>JSONDecoder</code>, you will be able to decode the JSON data into your specified instances. The below figure illustrates the decoding of a sample loan data into an instance of <code>Loan</code> using <code>JSONDecoder</code>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="735" src="https://www.appcoda.com/content/images/wordpress/2020/02/json-3-1024x735.png" alt="Working with JSON and Codable in Swift 5" class="wp-image-17725" srcset="https://www.appcoda.com/content/images/wordpress/2020/02/json-3-1024x735.png 1024w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-418x300.png 418w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-200x144.png 200w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-768x551.png 768w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-1536x1102.png 1536w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-1680x1206.png 1680w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-1240x890.png 1240w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-860x617.png 860w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-680x488.png 680w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-400x287.png 400w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3-50x36.png 50w, https://www.appcoda.com/content/images/wordpress/2020/02/json-3.png 1750w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading">Decoding JSON</h2>



<p>To give you a better idea about how <code>Codable</code> works, let&#x2019;s start a Playground project and write some code. Once you have created your Playground project, declare the following <code>json</code> variable:</p>



<pre class="wp-block-code"><code>let json = &quot;&quot;&quot;
{

&quot;name&quot;: &quot;John Davis&quot;,
&quot;country&quot;: &quot;Peru&quot;,
&quot;use&quot;: &quot;to buy a new collection of clothes to stock her shop before the holidays.&quot;,
&quot;amount&quot;: 150

}
&quot;&quot;&quot;</code></pre>



<p>We will first start with the basics. Here we define a very simple JSON data with 4 items. The value of the first three items are of the type <code>String</code> and the last one is of the type <code>Int</code>. As a side note, if this is the first time you see the pair of triple quotes (<code>&quot;&quot;&quot;</code>), this syntax was introduced in Swift 4 for declaring strings with multi-lines.</p>



<p>Next, declare the <code>Loan</code> structure like this:</p>



<pre class="wp-block-code"><code>struct Loan: Codable {
    var name: String
    var country: String
    var use: String
    var amount: Int
}</code></pre>



<p>This <code>Loan</code> structure is very similar to the one we defined in the previous section, except that it adopts the <code>Codable</code> protocol. You should also note that the property names match those of the JSON data.</p>



<p>Now, let&#x2019;s see the magic!</p>



<p>Continue to insert the following code in your Playground file:</p>



<pre class="wp-block-code"><code>let decoder = JSONDecoder()

if let jsonData = json.data(using: .utf8) {

    do {
        let loan = try decoder.decode(Loan.self, from: jsonData)
        print(loan)

    } catch {
        print(error)
    }
}</code></pre>



<p>In the code above, we instantiate an instance of <code>JSONDecoder</code> and then convert the JSON string we defined earlier into <code>Data</code>. The magic happens in this line of code:</p>



<pre class="wp-block-code"><code>let loan = try decoder.decode(Loan.self, from: jsonData)</code></pre>



<p>You just need to call the <code>decode</code> method of the decoder with the JSON data and specify the type of the value to decode (i.e. <code>Loan.self</code>). The decoder will automatically parse the JSON data and convert them into a <code>Loan</code> object.</p>



<p>If you&#x2019;ve done it correctly, you should see this line in the console:</p>



<pre class="wp-block-code"><code>Loan(name: &quot;John Davis&quot;, country: &quot;Peru&quot;, use: &quot;to buy a new collection of clothes to stock her shop before the holidays.&quot;, amount: 150)</code></pre>



<p>Cool, right? </p>



<p><code>JSONDecoder</code> automatically decodes the JSON data and stores the decoded value in the corresponding property of the specified type (here, it is <code>Loan</code>).</p>



<h2 class="wp-block-heading">Working with Custom Property Names</h2>



<p>Earlier, I showed you the simplest example of JSON decoding. However, the decoding process is not always so straightforward. Now, let&#x2019;s take a look another example. </p>



<p>Sometimes, the property name of your type and the key of the JSON data are not exactly matched. How can you perform the decoding?</p>



<p>Let&#x2019;s say, we define the <code>json</code> variable like this:</p>



<pre class="wp-block-code"><code>let json = &quot;&quot;&quot;
{

&quot;name&quot;: &quot;John Davis&quot;,
&quot;country&quot;: &quot;Peru&quot;,
&quot;use&quot;: &quot;to buy a new collection of clothes to stock her shop before the holidays.&quot;,
&quot;loan_amount&quot;: 150

}
&quot;&quot;&quot;</code></pre>



<p>In the JSON data, the key of the loan amount is changed from <code>amount</code> to <code>loan_amount</code>. How can we decode the data without changing the property name <code>amount</code> of <code>Loan</code>?</p>



<p>Now, update the <code>Loan</code> structure like this:</p>



<pre class="wp-block-code"><code>struct Loan: Codable {
    var name: String
    var country: String
    var use: String
    var amount: Int

    enum CodingKeys: String, CodingKey {
        case name
        case country
        case use
        case amount = &quot;loan_amount&quot;
    }
}</code></pre>



<p>To define the mapping between the key and the property name, you are required to declare an enum called <code>CodingKeys</code> that has a rawValue of type <code>String</code> and conforms to the <code>CodingKey</code> protocol. In the enum, you define all the property names of your model and their corresponding key in the JSON data. Say, the case <code>amount</code> is defined to map to the key <code>loan_amount</code>. If both the property name and the key of the JSON data are the same, you can omit the assignment.</p>



<p>If you&#x2019;ve changed the code correctly, you should be able to decode the updated JSON data with the following message found in the console:</p>



<pre class="wp-block-code"><code>Loan(name: &quot;John Davis&quot;, country: &quot;Peru&quot;, use: &quot;to buy a new collection of clothes to stock her shop before the holidays.&quot;, amount: 150)</code></pre>



<h2 class="wp-block-heading">Working with Nested JSON Objects</h2>



<p>The JSON data that we have worked on so far has only one level. In reality, the JSON data is usually more complex with multiple levels. Now let&#x2019;s see how we can decode nested JSON objects.</p>



<p>First, update the <code>json</code> variable like this:</p>



<pre class="wp-block-code"><code>let json = &quot;&quot;&quot;
{

&quot;name&quot;: &quot;John Davis&quot;,
&quot;location&quot;: {
&quot;country&quot;: &quot;Peru&quot;,
},
&quot;use&quot;: &quot;to buy a new collection of clothes to stock her shop before the holidays.&quot;,
&quot;loan_amount&quot;: 150

}
&quot;&quot;&quot;</code></pre>



<p>We&#x2019;ve made a minor change to the data by introducing the <code>location</code> key that has a nested JSON object with the nested key <code>country</code>. How can we decode this type of JSON data and retrieve the value of <code>country</code> from the nested object?</p>



<p>Now, modify the <code>Loan</code> structure like this:</p>



<pre class="wp-block-code"><code>struct Loan: Codable {
    var name: String
    var country: String
    var use: String
    var amount: Int

    enum CodingKeys: String, CodingKey {
        case name
        case country = &quot;location&quot;
        case use
        case amount = &quot;loan_amount&quot;
    }

    enum LocationKeys: String, CodingKey {
        case country
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)

        name = try values.decode(String.self, forKey: .name)

        let location = try values.nestedContainer(keyedBy: LocationKeys.self, forKey: .country)
        country = try location.decode(String.self, forKey: .country)

        use = try values.decode(String.self, forKey: .use)
        amount = try values.decode(Int.self, forKey: .amount)

    }
}</code></pre>



<p>Similar to what we have done earlier, we have to define an enum <code>CodingKeys</code>. For the case <code>country</code>, we specify to map to the key <code>location</code>. To handle the nested JSON object, we need to define an additional enumeration. In the code above, we name it <code>LocationKeys</code> and declare the case <code>country</code> that matches the key <code>country</code> of the nested object.</p>



<p>Since it is not a direct mapping, we need to implement the initializer of the <code>Decodable</code> protocol to handle the decoding of all properties. In the <code>init</code> method, we first invoke the <code>container</code> method of the decoder with <code>CodingKeys.self</code> to retrieve the data related to the specified coding keys, which are <code>name</code>, <code>location</code>, <code>use</code> and <code>amount</code>. </p>



<p>To decode a specific value, we call the <code>decode</code> method with the specific key (e.g. <code>.name</code>) and the associated type (e.g. <code>String.self</code>). The decoding of the <code>name</code>, <code>use</code> and <code>amount</code> is pretty straightforward. For the <code>country</code> property, the decoding is a little bit tricky. We have to call the <code>nestedContainer</code> method with <code>LocationKeys.self</code> to retrieve the nested JSON object.  From the values returned, we further decode the value of <code>country</code>.</p>



<p>That is how you decode JSON data with nested objects. If you&#x2019;ve followed me correctly, you should see the following message in the console:</p>



<pre class="wp-block-code"><code>Loan(name: &quot;John Davis&quot;, country: &quot;Peru&quot;, use: &quot;to buy a new collection of clothes to stock her shop before the holidays.&quot;, amount: 150)</code></pre>



<h2 class="wp-block-heading">Working with Arrays</h2>



<p>In the JSON data returned from Kiva API, it usually comes with more than one loan. Multiple loans are structured in the form of an array. Now, let&#x2019;s see how to decode an array of JSON objects using Codable.</p>



<p>First, modify the <code>json</code> variable like this:</p>



<pre class="wp-block-code"><code>let json = &quot;&quot;&quot;

[{
&quot;name&quot;: &quot;John Davis&quot;,
&quot;location&quot;: {
&quot;country&quot;: &quot;Paraguay&quot;,
},
&quot;use&quot;: &quot;to buy a new collection of clothes to stock her shop before the holidays.&quot;,
&quot;loan_amount&quot;: 150
},
{
&quot;name&quot;: &quot;Las Margaritas Group&quot;,
&quot;location&quot;: {
&quot;country&quot;: &quot;Colombia&quot;,
},
&quot;use&quot;: &quot;to purchase coal in large quantities for resale.&quot;,
&quot;loan_amount&quot;: 200
}]

&quot;&quot;&quot;</code></pre>



<p>To decode the above array into an array of <code>Loan</code> object, all you need to use is to modify the following line of code from:</p>



<pre class="wp-block-code"><code>let loan = try decoder.decode(Loan.self, from: jsonData)</code></pre>



<p>to:</p>



<pre class="wp-block-code"><code>let loans = try decoder.decode([Loan].self, from: jsonData)</code></pre>



<p>As you can see, you just need to specify <code>[Loan].self</code> when decoding the JSON data.</p>



<p>Now that the JSON data is fully utilized, but sometimes you may want to ignore some key/value pairs. Let&#x2019;s say, we update the <code>json</code> variable like this:</p>



<pre class="wp-block-code"><code>let json = &quot;&quot;&quot;
{
&quot;paging&quot;: {
&quot;page&quot;: 1,
&quot;total&quot;: 6083,
&quot;page_size&quot;: 20,
&quot;pages&quot;: 305
},
&quot;loans&quot;:
[{
&quot;name&quot;: &quot;John Davis&quot;,
&quot;location&quot;: {
&quot;country&quot;: &quot;Paraguay&quot;,
},
&quot;use&quot;: &quot;to buy a new collection of clothes to stock her shop before the holidays.&quot;,
&quot;loan_amount&quot;: 150
},
{
&quot;name&quot;: &quot;Las Margaritas Group&quot;,
&quot;location&quot;: {
&quot;country&quot;: &quot;Colombia&quot;,
},
&quot;use&quot;: &quot;to purchase coal in large quantities for resale.&quot;,
&quot;loan_amount&quot;: 200
}]
}
&quot;&quot;&quot;</code></pre>



<p>This JSON data comes with two top-level objects : <em>paging</em> and <em>loans</em>. Apparently, we are only interested in the data related to loans. In this case, how can you decode the array of loans?</p>



<p>To do that, declare another struct named <code>LoanDataStore</code> that also adopts <code>Codable</code>:</p>



<pre class="wp-block-code"><code>struct LoanDataStore: Codable {
    var loans: [Loan]
}</code></pre>



<p>This <code>LoanDataStore</code> only has a <code>loans</code> property that matches the key <code>loans</code> of the JSON data.</p>



<p>Now modify the following line of code from:</p>



<pre class="wp-block-code"><code>let loans = try decoder.decode([Loan].self, from: jsonData)</code></pre>



<p>to:</p>



<pre class="wp-block-code"><code>let loanDataStore = try decoder.decode(LoanDataStore.self, from: jsonData)</code></pre>



<p>The decoder will automatically decode the <code>loans</code> JSON objects and store them into the <code>loans</code> array of <code>LoanDataStore</code>. You can add the following lines of code to verify the content of the array:</p>



<pre class="wp-block-code"><code>for loan in loanDataStore.loans {
    print(loan)
}</code></pre>



<p>The console should have an output like this:</p>



<pre class="wp-block-code"><code>Loan(name: &quot;John Davis&quot;, country: &quot;Paraguay&quot;, use: &quot;to buy a new collection of clothes to stock her shop before the holidays.&quot;, amount: 150)
Loan(name: &quot;Las Margaritas Group&quot;, country: &quot;Colombia&quot;, use: &quot;to purchase coal in large quantities for resale.&quot;, amount: 200)</code></pre>



<h2 class="wp-block-heading">Using Codable in the KivaLoan App</h2>



<p>Now that I believe you have some ideas about how to decode JSON using Codable, let&#x2019;s go back to the KivaLoan project and modify it to use Codable.</p>



<p>Open <code>Loan.swift</code> and replace it with the following code:</p>



<pre class="wp-block-code"><code>import Foundation

struct Loan: Codable {

    var name: String = &quot;&quot;
    var country: String = &quot;&quot;
    var use: String = &quot;&quot;
    var amount: Int = 0

    enum CodingKeys: String, CodingKey {
        case name
        case country = &quot;location&quot;
        case use
        case amount = &quot;loan_amount&quot;
    }

    enum LocationKeys: String, CodingKey {
        case country
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)

        name = try values.decode(String.self, forKey: .name)

        let location = try values.nestedContainer(keyedBy: LocationKeys.self, forKey: .country)
        country = try location.decode(String.self, forKey: .country)

        use = try values.decode(String.self, forKey: .use)
        amount = try values.decode(Int.self, forKey: .amount)

    }
}


struct LoanDataStore: Codable {
    var loans: [Loan]
}</code></pre>



<p>The code above is exactly the same as the one we developed earlier. The <code>LoanDataStore</code> is designed to store an array of loans.</p>



<p>Next, replace the <code>parseJsonData</code> method of the <code>KivaLoanTableViewController</code> class with the following code:</p>



<pre class="wp-block-code"><code>func parseJsonData(data: Data) -&gt; [Loan] {

    var loans = [Loan]()

    let decoder = JSONDecoder()

    do {
        let loanDataStore = try decoder.decode(LoanDataStore.self, from: data)
        loans = loanDataStore.loans

    } catch {
        print(error)
    }

    return loans
}</code></pre>



<p>Here, we just use the <code>JSONDecoder</code> to decode the JSON data instead of <code>JSONSerialization</code>. I will not go into the code because it is the same as we have just worked on in the Playground project.</p>



<p>Now you&#x2019;re ready to hit the Run button and test the app in the simulator. Everything should be the same as before. Under the hood, the app now makes use of <code>Codable</code> in Swift 5 to decode JSON.</p>



<p><div class="alert gray"><strong>Editor&#x2019;s note</strong>: This is a <a href="https://www.appcoda.com/intermediate-swift-tips/">sample chapter</a> of the <a href="https://www.appcoda.com/intermediate-swift-programming-book/">Intermediate iOS 13 Programming with Swift</a> book.</div></p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[How to Create Perspective Text Using SwiftUI]]></title><description><![CDATA[<!--kg-card-begin: html-->
<p>If you&#x2019;ve worked with UIKit before, the&#xA0;<code>Text</code>&#xA0;control in SwiftUI is very similar to&#xA0;<code>UILabel</code>&#xA0;in UIKit. It&#x2019;s a view for you to display one or multiple lines of text. This&#xA0;<code>Text</code>&#xA0;control is non-editable but is useful for</p>]]></description><link>https://www.appcoda.com/swiftui-perspective-text/</link><guid isPermaLink="false">66612a0f166d3c03cf0114b6</guid><category><![CDATA[iOS Programming]]></category><category><![CDATA[SwiftUI]]></category><dc:creator><![CDATA[Simon Ng]]></dc:creator><pubDate>Fri, 22 Nov 2019 12:58:13 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2019/11/3rpooasqxmo.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: html-->
<img src="https://www.appcoda.com/content/images/wordpress/2019/11/3rpooasqxmo.jpg" alt="How to Create Perspective Text Using SwiftUI"><p>If you&#x2019;ve worked with UIKit before, the&#xA0;<code>Text</code>&#xA0;control in SwiftUI is very similar to&#xA0;<code>UILabel</code>&#xA0;in UIKit. It&#x2019;s a view for you to display one or multiple lines of text. This&#xA0;<code>Text</code>&#xA0;control is non-editable but is useful for presenting read-only information on screen. For example, you want to present an on-screen message, you can use&#xA0;<code>Text</code>&#xA0;to implement it.&#xA0;</p>



<p><a href="https://developer.apple.com/xcode/swiftui/?ref=appcoda.com">SwiftUI</a>, Apple&#x2019;s new declarative UI framework, has been officially released for around two months. If you still haven&#x2019;t explored the framework, this tutorial is written for you. In this tutorial, I&#x2019;ll show you how to work with&#xA0;<code>Text</code>&#xA0;to present information, customize it with your preferred color, and apply rotation effects to create perspective text.</p>



<p><div class="alert green"><strong>Editor&#x2019;s note</strong>: This tutorial is a <a href="https://www.appcoda.com/learnswiftui/swiftui-text.html">sample chapter</a> of the <a href="https://www.appcoda.com/swiftui">Mastering SwiftUI</a> book.</div></p>



<h2 class="wp-block-heading" id="creating-a-new-project-for-playing-with-swiftui">Creating a New Project for Playing with SwiftUI</h2>



<p>First, fire up Xcode and create a new project using the&#xA0;<em>Single View App</em> template. Type the name of the project. I set it to&#xA0;<em>SwiftUIText</em>&#xA0;but you&#x2019;re free to use any other name. For the organization name, you can set it to your company or organization. The organization identifier is a unique identifier of your app. Here I use&#xA0;<em>com.appcoda</em>&#xA0;but you should set to your own value. If you have a website, set it to your domain in reverse domain name notation. To use SwiftUI, you have to explicitly check the&#xA0;<em>Use SwiftUI</em>&#xA0;checkbox. Click&#xA0;<em>Next</em>&#xA0;and choose a folder to create the project.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="737" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-1024x737.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17452" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-1024x737.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-417x300.png 417w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-200x144.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-768x552.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-1240x892.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-860x619.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-680x489.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-400x288.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1-50x36.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-1.png 1454w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Once you save the project, Xcode should load the&#xA0;<code>ContentView.swift</code> file and display a design/preview canvas. If you can&#x2019;t see the design canvas, you can go up to the Xcode menu and choose&#xA0;<em>Editor</em>&#xA0;&gt;&#xA0;<em>Canvas</em>&#xA0;to enable it.</p>



<h2 class="wp-block-heading" id="displaying-a-simple-text">Displaying a Simple Text</h2>



<p>The sample code generated in&#xA0;<code>ContentView</code>&#xA0;already shows you how to display a single line of text. You initialize a&#xA0;<code>Text</code>&#xA0;and pass it with the text (e.g.&#xA0;<em>Hello World</em>) to display like this:</p>



<pre class="wp-block-code"><code>Text(&quot;Hello World&quot;)</code></pre>



<p>The preview canvas should display&#xA0;<em>Hello World</em>&#xA0;on screen. This is the basic syntax for creating a text view. You&#x2019;re free to change the text to whatever value you want and the canvas should show you the change instantaneously.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="380" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-1024x380.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17453" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-1024x380.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-600x223.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-200x74.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-768x285.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-1536x570.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-1680x624.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-1240x460.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-860x319.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-680x253.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-400x149.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3-50x19.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-3.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading" id="changing-the-font-type-and-color">Changing the Font Type and Color</h2>



<p>In SwiftUI, you can change the properties (e.g. color) of a control by calling methods that are known as&#xA0;<em>Modifiers</em>. Let&#x2019;s say, you want to bold the text. You can use the modifier named&#xA0;<code>fontWeight</code>&#xA0;and specify your preferred font weight (e.g.&#xA0;<code>.bold</code>) like this:</p>



<pre class="wp-block-code"><code>Text(&quot;Stay Hungry. Stay Foolish.&quot;).fontWeight(.bold)</code></pre>



<p>You access the modifier by using the dot syntax. Whenever you type a dot, Xcode will show you the possible modifiers or values you can use. For example, you will see various font weight options when you type a dot in the&#xA0;<code>fontWeight</code>&#xA0;modifier. You can choose&#xA0;<code>bold</code>&#xA0;to bold the text. If you want to make it even bolder, use&#xA0;<code>heavy</code>&#xA0;or&#xA0;<code>black</code>.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="375" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-1024x375.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17454" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-1024x375.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-600x220.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-200x73.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-768x282.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-1536x563.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-1680x616.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-1240x455.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-860x315.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-680x249.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-400x147.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4-50x18.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-4.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>By calling&#xA0;<code>fontWeight</code>&#xA0;with the value&#xA0;<code>.bold</code>, it actually returns you with a new view that has the bolded text. What&#x2019;s interesting in SwiftUI is that you can further chain this new view with other modifiers. Say, you want to make the bolded text a little bit bigger, you can write the code like this:</p>



<pre class="wp-block-code"><code>Text(&quot;Stay Hungry. Stay Foolish.&quot;).fontWeight(.bold).font(.title)</code></pre>



<p>Since we may chain multiple modifiers together, we usually write the code above in the following format:</p>



<pre class="wp-block-code"><code>Text(&quot;Stay Hungry. Stay Foolish.&quot;)
    .fontWeight(.bold)
    .font(.title)</code></pre>



<p>The functionality is the same but I believe you&#x2019;ll find the code above more easy to read. We will continue to use this coding convention for the rest of this book.</p>



<p>The&#xA0;<code>font</code>&#xA0;modifier lets you change the font properties. In the code above, we specify to use the&#xA0;<em>title</em>&#xA0;font type in order to enlarge the text. SwiftUI comes with several built-in text styles including&#xA0;<em>title</em>,&#xA0;<em>largeTitle</em>,&#xA0;<em>body</em>, etc. If you want to further increase the font size, replace&#xA0;<code>.title</code>&#xA0;with&#xA0;<code>.largeTitle</code>.&#xA0;</p>



<p><em>Note: You can always to refer the <a href="https://developer.apple.com/documentation/swiftui/font?ref=appcoda.com">documentation</a> to find out all the supported values of the&#xA0;<code>font</code>&#xA0;modifier.</em></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="401" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-1024x401.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17455" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-1024x401.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-600x235.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-200x78.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-768x300.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-1536x601.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-1680x657.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-1240x485.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-860x336.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-680x266.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-400x156.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5-50x20.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-5.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>You can also use the&#xA0;<code>font</code>&#xA0;modifier to specify the font design. Let&#x2019;s say, you want the font to be rounded. You can write the&#xA0;<code>font</code> modifier like this:</p>



<pre class="wp-block-code"><code>.font(.system(.largeTitle, design: .rounded))</code></pre>



<p>Here you specify to use the system font with&#xA0;<code>largeTitle</code>&#xA0;text style and&#xA0;<code>rounded</code>&#xA0;design. The preview canvas should immediately respond to the change and show you the rounded text.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="235" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6-1024x235.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17456" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6-1024x235.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6-600x137.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6-200x46.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6-768x176.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6-860x197.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6-680x156.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6-400x92.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6-50x11.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-6.png 1100w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Dynamic Type is a feature of iOS that automatically adjusts the font size in reference to the user&#x2019;s setting (Settings &gt; Display &amp; Brightness &gt; Text Size). In other words, when you use text styles (e.g.&#xA0;<code>.title</code>), the font size will be varied and your app will scale the text automatically, depending on the user&#x2019;s preference.</p>



<p>In case you want to use a fixed-size font, you can write the line of code like this:</p>



<pre class="wp-block-code"><code>.font(.system(size: 20))</code></pre>



<p>This tells the system to use a fixed font size of 20 points.</p>



<p>As said, you can continue to chain other modifiers to customize the text. Now let&#x2019;s change the font color. To do that, you can use the&#xA0;<code>foregroundColor</code>&#xA0;modifier like this:</p>



<pre class="wp-block-code"><code>.foregroundColor(.green)</code></pre>



<p>The&#xA0;<code>foregroundColor</code>&#xA0;modifier accepts a value of&#xA0;<code>Color</code>. Here we specify to use&#xA0;<code>.green</code>, which is a built-in color. You may use other built-in values like&#xA0;<code>.red</code>,&#xA0;<code>.purple</code>, etc.&#xA0;</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="294" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-1024x294.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17457" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-1024x294.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-600x173.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-200x58.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-768x221.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-1536x442.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-1680x483.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-1240x357.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-860x247.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-680x196.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-400x115.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7-50x14.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-7.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>While I prefer to customize the properties of a control using code, you can also use the design canvas to edit them. Hold the command key and click the text to bring up a pop-over menu. Choose&#xA0;<em>Inspect&#x2026;</em>&#xA0;and then you can edit the text/font properties.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="291" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-1024x291.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17458" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-1024x291.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-600x171.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-200x57.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-768x219.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-1536x437.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-1680x478.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-1240x353.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-860x245.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-680x193.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-400x114.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8-50x14.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-8.png 1940w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading" id="using-custom-fonts">Using Custom Fonts</h2>



<p>By default, all text are displayed using the system font. If you want to use other fonts, you can replace the following line of code:</p>



<pre class="wp-block-code"><code>.font(.system(size: 20))</code></pre>



<p>With:</p>



<pre class="wp-block-code"><code>.font(.custom(&quot;Helvetica Neue&quot;, size: 25))</code></pre>



<p>Instead of using&#xA0;<code>.system</code>, the code above use&#xA0;<code>.custom</code>&#xA0;and specify the preferred font name. The name of the font can be found in Font Book. You can open Finder &gt; Application and click&#xA0;<em>Font Book</em>&#xA0;to launch the app.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="533" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-1024x533.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17459" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-1024x533.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-576x300.png 576w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-200x104.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-768x400.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-1536x800.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-1680x875.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-1240x646.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-860x448.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-680x354.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-400x208.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9-50x26.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-9.png 1770w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading" id="working-with-multiline-text">Working with Multiline Text</h2>



<p><code>Text</code>&#xA0;supports multiple lines by default, so it can display a paragraph of text without using any additional modifiers. Replace the code with the following:</p>



<pre class="wp-block-code"><code>Text(&quot;Your time is limited, so don&#x2019;t waste it living someone else&#x2019;s life. Don&#x2019;t be trapped by dogma&#x2014;which is living with the results of other people&#x2019;s thinking. Don&#x2019;t let the noise of others&#x2019; opinions drown out your own inner voice. And most important, have the courage to follow your heart and intuition.&quot;)
    .fontWeight(.bold)
    .font(.title)
    .foregroundColor(.gray)</code></pre>



<p>You&#x2019;re free to replace the paragraph of text with your own value. Just make sure it&#x2019;s long enough. Once you made the change, the design canvas should render a multiline text label.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="349" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-1024x349.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17460" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-1024x349.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-600x205.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-200x68.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-768x262.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-1536x524.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-1680x573.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-1240x423.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-860x293.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-680x232.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-400x136.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10-50x17.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-10.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>To align the text in centre, insert the&#xA0;<code>multilineTextAlignment</code> modifier and set the value to&#xA0;<code>.center</code>&#xA0;like this:</p>



<pre class="wp-block-code"><code>.multilineTextAlignment(.center)</code></pre>



<p>In some cases, you may want to limit the number of lines to a certain number. You can use the&#xA0;<code>lineLimit</code>&#xA0;modifier to control it. Here is an example:</p>



<pre class="wp-block-code"><code>.lineLimit(3)</code></pre>



<p>By default, the system is set to use tail truncation. To modify the truncation mode of the text, you can use the&#xA0;<code>truncationMode</code>&#xA0;modifier and set its value to&#xA0;<code>.head</code>&#xA0;or&#xA0;<code>.middle</code>&#xA0;like this:</p>



<pre class="wp-block-code"><code>.truncationMode(.head)</code></pre>



<p>After the change, your text should look like the figure below.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="393" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-1024x393.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17461" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-1024x393.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-600x230.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-200x77.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-768x294.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-1536x589.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-1680x644.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-1240x475.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-860x330.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-680x261.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-400x153.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11-50x19.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-11.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Earlier, I mentioned that the&#xA0;<code>Text</code>&#xA0;control displays multiple lines by default. The reason is that the SwiftUI framework has set a default value of&#xA0;<code>nil</code>&#xA0;for the&#xA0;<code>lineLimit</code>&#xA0;modifier. You can change the value of&#xA0;<code>.lineLimit</code>&#xA0;to&#xA0;<code>nil</code>&#xA0;and see the result:</p>



<pre class="wp-block-code"><code>.lineLimit(nil)</code></pre>



<h2 class="wp-block-heading" id="setting-the-padding-and-line-spacing">Setting the Padding and Line Spacing</h2>



<p>Normally the default line spacing is good enough for most situations. In case you want to alter the default setting, you can adjust the line spacing by using the&#xA0;<code>lineSpacing</code>&#xA0;modifier.</p>



<pre class="wp-block-code"><code>.lineSpacing(10)</code></pre>



<p>As you see, the text is too close to the left and right side of the edges. To give it some more space, you can use the&#xA0;<code>padding</code>&#xA0;modifier, which adds some extra space for each side of the text. Insert the following line of code after the&#xA0;<code>lineSpacing</code>&#xA0;modifier:</p>



<pre class="wp-block-code"><code>.padding()</code></pre>



<p>Your design canvas should now show the result like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="382" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-1024x382.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17462" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-1024x382.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-600x224.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-200x75.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-768x286.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-1536x573.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-1680x627.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-1240x462.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-860x321.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-680x254.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-400x149.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12-50x19.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-12.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading" id="rotating-the-text">Applying Rotation Effect to Create Perspective Text</h2>



<p>The SwiftUI framework provides API to let you easily rotate the text. You can use the&#xA0;<code>rotateEffect</code>&#xA0;modifier and pass the rotation degree like this:</p>



<pre class="wp-block-code"><code>.rotationEffect(.degrees(45))</code></pre>



<p>If you insert the above line of code after&#xA0;<code>padding()</code>, you will see the text is rotated by 45 degrees.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="423" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-1024x423.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17463" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-1024x423.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-600x248.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-200x83.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-768x318.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-1536x635.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-1680x695.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-1240x513.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-860x356.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-680x281.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-400x165.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13-50x21.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-13.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>By default, the rotation happens around the center of the text view. If you want to rotate the text around a specific point (say, the top-left corner), you can write the code like this:</p>



<pre class="wp-block-code"><code>.rotationEffect(.degrees(20), anchor: UnitPoint(x: 0, y: 0))</code></pre>



<p>We pass an extra parameter&#xA0;<code>anchor</code>&#xA0;to specify the point of the rotation.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="410" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-1024x410.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17464" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-1024x410.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-600x240.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-200x80.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-768x307.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-1536x614.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-1680x672.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-1240x496.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-860x344.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-680x272.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-400x160.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14-50x20.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-14.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Not only can you rotate thee text in 2D, SwiftUI provides a modifier called&#xA0;<code>rotation3DEffect</code>&#xA0;that allows you to create some amazing 3D effect. The modifier takes in two parameters:&#xA0;<em>rotation angle and the axis of the rotation</em>. Say, you want to create a perspective text effect, you can write the code like this:</p>



<pre class="wp-block-code"><code>.rotation3DEffect(.degrees(60), axis: (x: 1, y: 0, z: 0))</code></pre>



<p>With just a line of code, you already re-create the Star Wars perspective text.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="409" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-1024x409.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17465" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-1024x409.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-600x239.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-200x80.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-768x306.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-1536x613.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-1680x670.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-1240x495.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-860x343.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-680x271.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-400x160.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15-50x20.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-15.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>You can further insert the following line of code to create a drop shadow effect for the perspective text:</p>



<pre class="wp-block-code"><code>.shadow(color: .gray, radius: 2, x: 0, y: 15)</code></pre>



<p>The&#xA0;<code>shadow</code>&#xA0;modifier will apply the shadow effect to the text. All you need to do is specify the color and radius of the shadow. Optionally, you can tell the system the position of the shadow by specifying the&#xA0;<code>x</code>&#xA0;and&#xA0;<code>y</code>&#xA0;values.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="411" src="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-1024x411.png" alt="How to Create Perspective Text Using SwiftUI" class="wp-image-17466" srcset="https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-1024x411.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-600x241.png 600w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-200x80.png 200w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-768x308.png 768w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-1536x617.png 1536w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-1680x675.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-1240x498.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-860x345.png 860w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-680x273.png 680w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-400x161.png 400w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16-50x20.png 50w, https://www.appcoda.com/content/images/wordpress/2019/11/swiftui-text-16.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h3 class="wp-block-heading" id="summary">Summary</h3>



<p>Do you enjoy creating user interface with SwiftUI? I hope so. The declarative syntax of SwiftUI made the code more readable and easier to understand. As you can see, it only takes a few lines of code in SwiftUI to create fancy text in 3D style.</p>



<p>If you want to learn more about SwiftUI, please check out our new book &#x2013; <a href="https://www.appcoda.com/swiftui">Mastering SwiftUI</a>.</p>



<p><strong>Editor&#x2019;s note</strong>: We&#x2019;ve added a <a href="https://www.appcoda.com/star-wars-animated-text-swiftui/">new tutorial</a> to show you how to animate the perspective text like that in Star Wars.</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[A Complete Guide to In-App Purchases for iOS Development]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>Hello folks! In a time where the App Store is full of apps, users have more than plenty of options to choose from. There is a lot of competition on all kind of apps, and users want to try them before they decide whether they like them or not. On</p>]]></description><link>https://www.appcoda.com/in-app-purchases-guide/</link><guid isPermaLink="false">66612a0f166d3c03cf0114b3</guid><category><![CDATA[iOS Programming]]></category><category><![CDATA[Swift]]></category><dc:creator><![CDATA[Gabriel Theodoropoulos]]></dc:creator><pubDate>Fri, 25 Oct 2019 19:55:24 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2019/10/pxwpjdy8irg.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2019/10/pxwpjdy8irg.jpg" alt="A Complete Guide to In-App Purchases for iOS Development"><p>Hello folks! In a time where the App Store is full of apps, users have more than plenty of options to choose from. There is a lot of competition on all kind of apps, and users want to try them before they decide whether they like them or not. On the other hand, developers target on making some profit out of their published apps, but first they need to build an audience for that. Releasing an app as a paid one is not something that guarantees a financial success; unless the app is doing something extraordinary, chances that users will pay for it are low. Thankfully, there is a solution which is satisfying for both sides so users can try apps and developers see some profit; it&#x2019;s called <strong>In-App Purchases</strong>.</p>



<p><div class="alert gray">Editor&#x2019;s note: This guide provides an extensive update to <a href="https://www.appcoda.com/in-app-purchase-tutorial/">the original guide of In-app purchases</a>.</div></p>



<p>By offering <a href="https://developer.apple.com/in-app-purchase/?ref=appcoda.com">in-app purchases</a> to an app, we, as developers, can keep content or features locked, hidden or unavailable from users unless they pay for it. Users on their side are happy because they can have a taste of the app using its free parts, and they&#x2019;ll be willing to buy the premium content if they&#x2019;re satisfied by it.</p>



<p>Any purchasable digital item through in-app purchases is called a <em>product</em>. App Store offers four different kind of products:</p>



<ol><li><em>Consumable</em>: These are products which can be bought again and again after users have <em>consumed</em> them.</li><li><em>Non-consumable</em>: These are products bought just once. In subsequent app installations users do not pay again to acquire them; instead these products are <em>restored</em> from the App Store.</li><li><em>Auto-renewable subscriptions</em>: Users can buy content or features for a certain period of time. Upon expiration, subscription is renewed automatically. Users have always the option to cancel.</li><li><em>Non-renewing subscriptions</em>: Similar as above, but the subscription does not renew automatically. The content of the in-app purchase also differs.</li></ol>



<p>In this tutorial we won&#x2019;t discuss at all about subscriptions; We&#x2019;ll focus on consumable and non-consumable products only because it would be impossible to cover everything in just one tutorial.</p>



<p>When using IAPs, it&#x2019;s possible to have additional <em>downloadable</em> content that users get only after paying for it. This content can be stored either on your server or in Apple&#x2019;s servers. That&#x2019;s also a case which we won&#x2019;t cover, but I invite you to extend what we&#x2019;ll do in this tutorial when finishing it and add any missing features if you want so.</p>



<p>Integrating and providing in-app purchases to an app is not a difficult task; it just includes several steps in the way. If you haven&#x2019;t done that before then you might find it complicated, but trust me that it&#x2019;s not. Keep reading to learn about the demo application we&#x2019;ll be using today, and get prepared to implement your first in-app purchases!</p>



<h2 class="wp-block-heading">About The Demo App</h2>



<p>The demo application we&#x2019;ll be building on in this tutorial is about a part of a <em>hypothetical, fake game</em>. Among the hypothetically provided features, it offers three in-app purchases (these are for real) that let users do the following:</p>



<ol><li>Buy extra lives.</li><li>Buy extra super powers.</li><li>Unlock all maps in the game.</li></ol>



<p>You&#x2019;re invited to unleash your imagination and write the plot of the game!</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="571" height="1024" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_1_app_screen-571x1024.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17336" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_1_app_screen-571x1024.png 571w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_1_app_screen-200x359.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_1_app_screen-167x300.png 167w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_1_app_screen-400x718.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_1_app_screen-50x90.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_1_app_screen.png 584w" sizes="(max-width: 571px) 100vw, 571px"></figure></div>



<p>The first two purchases regard <em>consumable</em> products, meaning products that can be bought again and again once they&#x2019;re consumed. The last one about unlocking all maps, is a non-consumable product which can be bought only once by users.</p>



<p>In order to keep things simple, contents are displayed in a <em>table view</em> with three cells. You can see in the above screenshot that the first two regard the consumable purchases, while the last one the non-consumable one. Tapping on the first two cells has a double role:</p>



<ul><li>If no extra lives or super powers have been purchased, then by tapping on them the in-app purchase process will begin.</li><li>If extra lives or super powers have been purchased, then tapping on the matching cells will decrease the number of the available lives or super powers respectively until they become zero. Then they&#x2019;ll be available to be bought again.</li></ul>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="571" height="1024" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_2_app_used-571x1024.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17337" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_2_app_used-571x1024.png 571w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_2_app_used-200x359.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_2_app_used-167x300.png 167w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_2_app_used-400x718.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_2_app_used-50x90.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_2_app_used.png 584w" sizes="(max-width: 571px) 100vw, 571px"></figure>



<p>As you understand, our goal here is to make the in-app purchases working and the process described right above to be fully functional. Most importantly, by finishing the IAP related implementation, we&#x2019;ll end up with a class that can be <em>reused</em> as-is or with slight modifications on any project after that.</p>



<p>There&#x2019;s a <a href="https://github.com/appcoda/In-app-Purchase-Game-Demo/raw/master/FakeGameStarter.zip?ref=appcoda.com">starter project</a> for you to download. It contains all the parts of the demo app which are not directly related to in-app purchases already implemented. When you get it, open it in Xcode. For your information, the project was made in Xcode 11.1.</p>



<p>Even though the demo project is really simple, it&#x2019;s built based on the <em>MVVM architecture</em> so it&#x2019;s easier to focus on the various parts of it. Take a look around and familiarize yourself with it. You might find interesting the <code>GameData</code> struct which is defined in the <code>Model</code> class in the <em>Model.swift</em> file. The <code>gameData</code> instance of this structure keeps the data that regard the purchased products. <code>GameData</code> structure adopts the <code>SettingsManageable</code> protocol for saving the values of its properties locally. That protocol was presented on a previous tutorial <a href="https://www.appcoda.com/swift-protocols-app-configuration/">about how to use protocols to manage app configuration</a>.</p>



<p><em>Note: The way you&#x2019;ll store any data regarding in-app purchases is always a matter totally dependent on your app itself and the available mechanisms to save data locally. What I strongly advice to avoid is using User Defaults as your storage solution.</em></p>



<p>With the above said, get ready to learn how to implement in-app purchases into your apps; it&#x2019;s going to be an interesting exploration from start to finish!</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="577" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1024x577.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17338" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1024x577.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-200x113.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-532x300.png 532w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-768x433.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1680x947.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1240x699.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-860x485.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-680x383.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-400x225.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-50x28.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading">Preparing In-App Purchases On The App Store</h2>



<p>The first thing we have to do before we start writing code in Xcode is to create the in-app purchase products that we&#x2019;ll be offering through the app. This is an action taking place on App Store, where we are going to create <em>a new app</em> (or app record) on it. Besides that, there are a couple of other steps included in the whole process of getting prepared for in-app purchases integraton.</p>



<p>In summary the actions we&#x2019;ll take before we switch to Xcode are:</p>



<ol><li>Create a new app identifier.</li><li>Take care of any pending agreements on the App Store.</li><li>Create test users for the in-app purchases.</li><li>Create a new app record on the App Store.</li><li>Create the actual in-app purchases.</li></ol>



<p>Let&#x2019;s see them now in detail.</p>



<h3 class="wp-block-heading">Creating A New App Identifier</h3>



<p>An <em>app identifier</em> is a unique string value that identifies an application on the App Store. It <em>refers to a specific application</em> and it&#x2019;s related to it through the <em>Bundle identifier</em> of the app. You can find it in the Project Editor under the <em>General tab</em> in Xcode; it&#x2019;s the <em>com.appcoda.FakeGame</em> value in the starter project.</p>



<p>An app identifier is necessary when creating new apps for the App Store. Let&#x2019;s create one now, therefore get connected to your <a href="http://developer.apple.com/account/?ref=appcoda.com">Apple developer account</a> in your favorite browser. Once you&#x2019;re in, click on the <strong>Certificates, IDs &amp; Profiles</strong> link in the options on the left.</p>



<p>In the next screen, click on the <strong>Identifiers</strong> menu item, and then click on <em>small blue plus button</em> to create a new one.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="862" height="346" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_5_identifiers_screen.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17339" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_5_identifiers_screen.png 862w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_5_identifiers_screen-200x80.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_5_identifiers_screen-600x241.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_5_identifiers_screen-768x308.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_5_identifiers_screen-860x345.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_5_identifiers_screen-680x273.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_5_identifiers_screen-400x161.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_5_identifiers_screen-50x20.png 50w" sizes="(max-width: 862px) 100vw, 862px"></figure>



<p>You&#x2019;ll be presented with a list of various types of identifiers to choose from. What we need is the first one, so make sure to click on the <strong>App IDs</strong> and then press Continue.</p>



<p>It&#x2019;s time to create the identifier. Make sure to fill in two fields:</p>



<ol><li>The <strong>Description</strong> of the app identifier. Feel free to provide any description you think it&#x2019;s best, just respect the limitations shown right below the field. For example, what I wrote in that field is: &#x201C;<em>FakeGame App ID for IAP Demo App by AppCoda</em>&#x201C;.</li><li>Next, in the <strong>Bundle ID</strong> keep the <strong>Explicit</strong> radio selected, and <strong>copy-and-paste the Bundle identifier</strong> from Xcode to that field.</li></ol>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="293" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id-1024x293.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17340" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id-1024x293.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id-200x57.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id-600x171.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id-768x220.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id-860x246.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id-680x194.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id-400x114.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id-50x14.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_7_register_app_id.png 1214w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Finally, click <em>Continue</em> and then in the last step click <strong>Register</strong>. By going back to the list of the app identifiers, you should be able to see the one that we just created!</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="293" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id-1024x293.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17341" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id-1024x293.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id-200x57.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id-600x172.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id-768x220.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id-860x246.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id-680x194.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id-400x114.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id-50x14.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_8_listed_app_id.png 1084w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h3 class="wp-block-heading">Fix Any Pending Agreements</h3>



<p>Let&#x2019;s leave the developer&#x2019;s account now and let&#x2019;s go to the App Store, also known as the <a href="listed_app_id"><em>iTunesConnect</em></a>. If you did not sign out from the developer&#x2019;s account then you&#x2019;ll be automatically connected, otherwise just provide your credentials to sing in again. Here&#x2019;s the place where we&#x2019;ll create a new record for our application and we&#x2019;ll setup the in-app purchases, as well as the place to perform a few more necessary actions. One of them is to check if you have any <em>pending agreements</em> that should be taken care of, like for example the next one:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="146" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-1024x146.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17342" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-1024x146.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-200x28.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-600x85.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-768x109.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-1240x177.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-860x122.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-680x97.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-400x57.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement-50x7.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_9_pending_agreement.png 1278w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Notifications like the one illustrated right above contain links to the page you should visit so you can accept the agreement(s). You can also go there on your own if you select the <strong>Agreements, Tax, and Banking</strong> options on the home screen of the App Store:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="509" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option-1024x509.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17343" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option-1024x509.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option-200x99.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option-600x298.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option-768x381.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option-860x427.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option-680x338.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option-400x199.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option-50x25.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_10_agreements_option.png 1182w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Once you get there, find the agreement or any other pending task (such as setting up a bank account) and proceed to the suggested or required actions so you eliminate all issues.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="143" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-1024x143.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17344" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-1024x143.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-200x28.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-600x84.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-768x107.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-1680x234.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-1240x173.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-860x120.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-680x95.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-400x56.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_11_agreement_to_fix-50x7.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Even though it&#x2019;s not necessary to have the above fixed when you&#x2019;re creating and testing in-app purchases, you still have to take care about it if you&#x2019;re planning to send your app either for testing to TestFlight, or to release it.</p>



<h3 class="wp-block-heading">Create Test Users</h3>



<p>Until an app is released on the App Store, all in-app purchases should be tested in a <em>sandbox mode</em> and neither you nor anyone else testing should pay with real money. By default, external testers who test in-app purchases through TestFlight don&#x2019;t actually pay when they are asked to. However, internal testers like the developers of an app should be using <em>test user accounts</em> and not their real Apple ID and iCloud accounts.</p>



<p>Creating test users in the App Store it&#x2019;s easy, however there&#x2019;s a <em>negative point</em>: Even though we&#x2019;re talking about <em>fake</em> accounts, <em>real email addresses are required</em>. A confirmation email is sent by Apple which should be validated before any test account is used!</p>



<p>So, if you want to have multiple test users it might be a bit of a hassle to have the same number of email addresses. I&#x2019;d recommend to check if your email service provider allows to use <em>aliases</em> along with your normal email address (as <em>GMail</em> does for example). If you have a paid server service (shared hosted, dedicated, or a personal one), then things are easier for you as you can create as many temporary email addresses as you want if you don&#x2019;t like using aliases, and then delete them easily.</p>



<p>Onto the actual process now, select the <strong>Users and Accesses</strong> option in the home screen of the App Store. In the next one, you&#x2019;ll find out a section called <strong>Sandbox</strong> to the left menu, and right below a link titled <strong>Testers</strong>:</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="496" height="548" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_12_testers_menu.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17345" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_12_testers_menu.png 496w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_12_testers_menu-200x221.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_12_testers_menu-272x300.png 272w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_12_testers_menu-400x442.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_12_testers_menu-50x55.png 50w" sizes="(max-width: 496px) 100vw, 496px"></figure></div>



<p>By clicking on it you&#x2019;ll be taken in the test users page. There&#x2019;s a <strong>blue plus button</strong> on top that you should press. You then fill in the information for the new tester.</p>



<p>If you&#x2019;re about to create multiple users, then I&#x2019;d suggest to choose different App Store territories so you can test in-app purchases with different currencies. Also, <em>make sure to remember the password you set</em>, because there&#x2019;s no way to edit this form again. You&#x2019;ll have to start over if you forget a test user&#x2019;s password.</p>



<p>When you&#x2019;re done typing the test user&#x2019;s information, click on the <em>Invite</em> button and wait for a confirmation email to come. Repeat the process by completing a new form for each new tester account you need to add.</p>



<p>Created test accounts are listed as shown next. You can remove them by clicking on the <em>Edit</em> button on the top-right side of the window, but you cannot edit them.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="479" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-1024x479.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17346" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-1024x479.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-200x93.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-600x280.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-768x359.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-1240x579.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-860x402.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-680x318.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-400x187.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users-50x23.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_14_listed_test_users.png 1269w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h3 class="wp-block-heading">Create A New App On The App Store</h3>



<p>Let&#x2019;s go now to some more juicy stuff, and let&#x2019;s create a new app record on the App Store which we&#x2019;ll connect to the actual iOS application. Get started by clicking on the <strong>My Apps</strong> option on the home screen of the App Store. Then, click on the <strong>Plus button</strong> on the top-left side of the top bar.</p>



<p>In the form that shows up, there are four fields that have to be mandatorily filled in:</p>



<ol><li>The name of the app. Make sure to provide a <strong>unique app name</strong>! If you provide a name already taken you&#x2019;ll see an error message when you&#x2019;ll try to create the app, so just go and change it.</li><li>The primary language the app is using.</li><li>The Bundle ID. Use the drop down menu to locate the <em>app ID</em> we created earlier which is connected to the Bundle Identifier of the app.</li><li>The <em>SKU</em> &#x2013; a unique string for the app not visible on the App Store.</li></ol>



<p>Also, make sure to select the <strong>iOS checkbox</strong> in the <em>Platforms</em> section.</p>



<p>Right below you can see the form completed. Use it as a guide and fill it in on your side too.</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="564" height="595" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_16_new_app_form.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17347" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_16_new_app_form.png 564w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_16_new_app_form-200x211.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_16_new_app_form-284x300.png 284w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_16_new_app_form-400x422.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_16_new_app_form-50x53.png 50w" sizes="(max-width: 564px) 100vw, 564px"></figure></div>



<p>If there&#x2019;s no missing data and the name you provided is unique, then a new app will be created right after you click on the <em>Create</em> button. You&#x2019;ll automatically be navigated to the <em>app information</em> page:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="723" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-1024x723.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17348" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-1024x723.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-200x141.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-425x300.png 425w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-768x542.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-1240x876.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-860x607.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-680x480.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-400x282.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page-50x35.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_17_app_info_page.png 1446w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h3 class="wp-block-heading">Adding In-App Purchases</h3>



<p>The most wanted time is finally here! In this part we&#x2019;ll create the in-app purchases that our app is going to offer. Before we do that, let&#x2019;s recap on what exactly we&#x2019;re going to provide:</p>



<ul><li>A <em>consumable</em> in-app purchase for buying three lives to use in the game.</li><li>A <em>consumable</em> in-app purchase for buying two super powers.</li><li>A <em>non-consumable</em> in-app purchase for unlocking all game maps.</li></ul>



<p>With all the above in mind, let&#x2019;s start creating them. Click on the <strong>Features</strong> link in the top bar, and then make sure that the <strong>In-App Purchases</strong> is selected on the left menu options.</p>



<p>The main area of the screen is where in-app purchases entries are going to be listed. At the time being there&#x2019;s none, so click the <strong>blue plus button</strong> to add one. The following popup will ask you to select the kind of in-app purchase you want to create, so click on the <strong>Consumable</strong> radio button and then on Create.</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="723" height="605" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_19_select_iap_type.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17349" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_19_select_iap_type.png 723w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_19_select_iap_type-200x167.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_19_select_iap_type-359x300.png 359w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_19_select_iap_type-680x569.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_19_select_iap_type-400x335.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_19_select_iap_type-50x42.png 50w" sizes="(max-width: 723px) 100vw, 723px"></figure></div>



<p>A new empty form to fill in is appearing once again. Let&#x2019;s go through its fields and what they&#x2019;re all about:</p>



<ul><li><strong>Reference Name</strong>: It&#x2019;s the name of the in-app purchase on the App Store, but it&#x2019;s for internal use only. It won&#x2019;t be shown to the users so don&#x2019;t worry too much about the value you will provide here. However, give a name that makes clear what this in-app purchase regards. For example, &#x201C;<em>Extra Lives</em>&#x201D; (without the quotes) is a good name to make us understand that this one is about the additional lives a user can buy in the game.</li><li><strong>Product ID</strong>: This must be a unique string (alphanumeric as Apple says) that will be used for reporting, but here&#x2019;s a recommendation: <em>Use the app&#x2019;s bundle identifier as a prefix to the ID value you will specify here</em>. That way you ensure that it&#x2019;ll always be unique. In our case, &#x201C;<em>com.appcoda.fakegame.extra-lives</em>&#x201D; (without quotes) is a unique product ID. <strong>Important</strong>: Note the product IDs you create here somewhere, we&#x2019;re going to need them later on.</li><li><strong>Cleared for Sale</strong>: Keep it always selected if you want the in-app purchase to be available to the public.</li><li><strong>Pricing</strong>: Select the price you want for your in-app purchase. Since this is just a demo, choose any price you would like from the drop down menu. Scroll to bottom to find alternative prices as well.</li><li><strong>App Store Information &#x2013; Display Name</strong>: This is the name of the in-app purchase as it will be shown to users in the app. Note this: For each supported language in your app, you should provide a localized version of this and the next field as well. The value I set here for the first in-app purchase is &#x201C;<em>Get Extra Lives</em>&#x201C;.</li><li><strong>App Store Information &#x2013; Description</strong>: A description of the in-app purchase publicly shown, but also optional to be presented by the app. I would recommend to always show it to your users so they can get more details on what they&#x2019;re about to purchase. For example: &#x201C;<em>Acquire three (3) additional lives!</em>&#x201C;.</li></ul>



<p>Here it is completed:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="446" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-1024x446.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17350" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-1024x446.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-200x87.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-600x261.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-768x335.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-1680x732.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-1240x540.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-860x375.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-680x296.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-400x174.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1-50x22.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_20_iap_completed_1.png 2001w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>By scrolling to the bottom of the page you&#x2019;ll notice two more sections lying there:</p>



<ul><li><strong>App Store Promotion (Optional)</strong>: By default, right below the app&#x2019;s name on the App Store there will be a string saying something like: &#x201C;Free &#x2013; Offers In-App Purchases&#x201D;. However, if you want to advertise the offered in-app purchases in the app&#x2019;s page on the App Store, then provide a promotional image as described by Apple.</li><li><strong>Review Information</strong>: This is not required when implementing and testing in-app purchases, but <em>it&#x2019;s required when an in-app purchase is about to be reviewed</em> either for releasing it to the App Store along with the app, or for TestFlight testing. <strong>Review Notes</strong> are not mandatory to be provided, however a <strong>Screenshot</strong> is needed. You can take a screenshot of the app where in-app purchases are offered and upload it, it&#x2019;ll be suffice. For now, however, leave it empty; we can proceed without it.</li></ul>



<p>When you finish providing the in-app purchase details, click on the <strong>Save</strong> button you will find on the top-right side of the form. Then go back and start creating the second in-app purchase. Select a <em>consumable</em> IAP again, and fill in the form using the following information:</p>



<ul><li><em>Reference Name</em>: Super Powers</li><li><em>Product ID</em>: com.appcoda.fakegame.superpowers <em>(change it according to your own Bundle ID)</em></li><li><em>Price</em>: Any price you want</li><li><em>Display Name</em>: Additional Super Powers</li><li><em>Description</em>: Get two (2) additional super powers!</li></ul>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="444" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-1024x444.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17351" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-1024x444.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-200x87.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-600x260.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-768x333.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-1680x729.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-1240x538.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-860x373.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-680x295.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-400x174.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2-50x22.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_22_iap_completed_2.png 2003w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Save this in-app purchase, and then create the last one. This time, select a <em>non-consumable</em> one:</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="720" height="150" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_23_non_consumable_iap.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17352" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_23_non_consumable_iap.png 720w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_23_non_consumable_iap-200x42.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_23_non_consumable_iap-600x125.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_23_non_consumable_iap-680x142.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_23_non_consumable_iap-400x83.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_23_non_consumable_iap-50x10.png 50w" sizes="(max-width: 720px) 100vw, 720px"></figure></div>



<p>On the contrary of the previous two, this is a kind of purchase that each user will make once. However, this doesn&#x2019;t change the way it&#x2019;s being set up. The exact same kind of data must be given in this case too:</p>



<ul><li><em>Reference Name</em>: Unlock All Maps</li><li><em>Product ID</em>: com.appcoda.fakegame.unlock_maps <em>(change it according to your own Bundle ID)</em></li><li><em>Price</em>: Any price you want</li><li><em>Display Name</em>: Unlock Maps</li><li><em>Description</em>: Unlock all maps in the game forever!</li></ul>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="517" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-1024x517.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17353" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-1024x517.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-200x101.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-594x300.png 594w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-768x388.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-1680x849.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-1240x626.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-860x435.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-680x344.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-400x202.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3-50x25.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_24_iap_completed_3.png 2005w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>The in-app purchases that our app will be offering are now ready and you can find them all together listed in the IAP home page:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="164" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-1024x164.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17354" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-1024x164.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-200x32.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-600x96.png 600w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-768x123.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-1240x198.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-860x137.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-680x109.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-400x64.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed-50x8.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_25_iap_listed.png 1645w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>You&#x2019;ll notice that the <em>Status</em> of all in-app purchases is set to <em>Missing Metadata</em>. That&#x2019;s because we didn&#x2019;t set a <em>review image</em> to any of them. Don&#x2019;t worry though, by adding a review image and saving the status will change to <em>Waiting For Review</em>. Such an action isn&#x2019;t necessary here; we&#x2019;re not going to publish this demo app.</p>



<h2 class="wp-block-heading">Using Product IDs In Xcode</h2>



<p>Finally, all necessary preparation has come to its end. It&#x2019;s now time to leave App Store and go to the starter project in Xcode. The final goal in this post is to create a reusable class that will manage in-app purchases, but this class will need to know about the available <em>product identifiers</em> created on the App Store. So, let&#x2019;s start with that and let&#x2019;s add all IAP product identifiers to a special file you&#x2019;ll find in Xcode under the <em>In-App Purchases group</em>, called <em>IAP_ProductIDs.plist</em>.</p>



<p>The purpose of this file is to let us keep product identifiers gathered in one place, in a simple and code-unrelated fashion. The class we&#x2019;ll implement next will get all product identifiers by just reading the contents of this file.</p>



<p>So, open <em>IAP_ProductIDs.plist</em> in Xcode and make sure that the <strong>type</strong> of the <em>Root</em> item is set to <strong>Array</strong>. Then, add three items one after another, and each time copy and paste the product ID of a different in-app purchase created earlier. In the end you should end up with this:</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="557" height="109" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_26_product_ids_plist.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17355" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_26_product_ids_plist.png 557w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_26_product_ids_plist-200x39.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_26_product_ids_plist-400x78.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_26_product_ids_plist-50x10.png 50w" sizes="(max-width: 557px) 100vw, 557px"></figure></div>



<h2 class="wp-block-heading">Start Implementing The In-App Purchases Managing Class</h2>



<p>Let&#x2019;s focus on implementing the reusable class now that will manage in-app purchases in our demo app and not only. In the starter project in Xcode, open the file called <em>IAPManager.swift</em> which you&#x2019;ll also find under the <em>In-App Purchases</em> group in Project Navigator. It&#x2019;s currently empty, but we&#x2019;ll change that here and in the following parts.</p>



<p>The first move is to import the <em>StoreKit</em> framework; it&#x2019;s the one that will allow us to deal with all in-app purchase related concepts and entities in programming level. Right after the first <code>import</code> statement add the following:</p>



<pre class="wp-block-code"><code>import StoreKit</code></pre>



<p>Let&#x2019;s declare the new class now which will have the same name to the file: <em>IAPManager</em>. Leave a couple of empty lines and add this:</p>



<pre class="wp-block-code"><code>class IAPManager: NSObject {

}</code></pre>



<p><em>Note: Later on the <code>IAPManager</code> class will adopt a protocol called <code>SKPaymentTransactionObserver</code>. This protocol requires any conforming types to also conform to <code>NSObjectProtocol</code>, and that&#x2019;s something we can do with no hassle simply by just making <code>IAPManager</code> a subclass of the <code>NSObject</code> class.</em></p>



<p>In order to keep things simple and to avoid potential troubles by having multiple instances of this class, we&#x2019;ll apply the <em>Singleton</em> pattern and we&#x2019;ll be using <em>one instance only</em>, the <em>shared instance</em>. Adopting the Singleton pattern requires two things:</p>



<ol><li>To have an instance of the class initialized as a static property.</li><li>Keep the initializer <em>private</em> so no more instances of the class can be created anywhere in the app.</li></ol>



<p>Here it is:</p>



<pre class="wp-block-code"><code>class IAPManager: NSObject {
    static let shared = IAPManager()

    private override init() {
        super.init()
    }
}</code></pre>



<p>As you will see next, there will be cases where the various operations won&#x2019;t return the desired or expected results. It&#x2019;s important to treat these cases gracefully and make <code>IAPManager</code> class indicate them properly in any custom type using it. For that purpose, we&#x2019;re going to create the following <code>enum</code> with a few <em>custom errors</em>:</p>



<pre class="wp-block-code"><code>enum IAPManagerError: Error {
    case noProductIDsFound
    case noProductsFound
    case paymentWasCancelled
    case productRequestFailed
}</code></pre>



<p>Make sure to add the enum <em>inside</em> the class body. The meaning of them:</p>



<ul><li><code>noProductIDsFound</code>: It indicates that the product identifiers could not be found.</li><li><code>noProductsFound</code>: No IAP products were returned by the App Store because none was found.</li><li><code>paymentWasCancelled</code>: The user cancelled an initialized purchase process.</li><li><code>productRequestFailed</code>: The app cannot request App Store about available IAP products for some reason.</li></ul>



<p>Along with the above enum, it&#x2019;s necessary to add the following extension <em>right after the closing of the <code>IAPManager</code> class</em>. In it, the <em>localized descriptions</em> of the custom errors are specified:</p>



<pre class="wp-block-code"><code>extension IAPManager.IAPManagerError: LocalizedError {
    var errorDescription: String? {
        switch self {
        case .noProductIDsFound: return &quot;No In-App Purchase product identifiers were found.&quot;
        case .noProductsFound: return &quot;No In-App Purchases were found.&quot;
        case .productRequestFailed: return &quot;Unable to fetch available In-App Purchase products at the moment.&quot;
        case .paymentWasCancelled: return &quot;In-App Purchase process was cancelled.&quot;
        }
    }
}</code></pre>



<h2 class="wp-block-heading">Reading Product Identifiers</h2>



<p>Before we perform any action related to in-app purchases, it&#x2019;s necessary to get the product identifiers that we previously added to the <em>IAP_ProductIDs.plist</em> file. For that purpose, we&#x2019;ll implement a small helper method that will do just that: Reading the property list file from the <em>app bundle</em> and returning the product identifiers as <em>an array of String elements</em>.</p>



<pre class="wp-block-code"><code>fileprivate func getProductIDs() -&gt; [String]? {

}</code></pre>



<p>The method is marked as <code>fileprivate</code> because we want it to be visible in this file only. There&#x2019;s no reason to be accessible by other entities out of this class. However, remove the <code>fileprivate</code> keyword if you ever need to have the product identifiers available somewhere else besides here.</p>



<p>The first step in this method is to get a <em>URL</em> pointing to the <em>IAP_ProductIDs.plist</em> file in the app bundle:</p>



<pre class="wp-block-code"><code>guard let url = Bundle.main.url(forResource: &quot;IAP_ProductIDs&quot;, withExtension: &quot;plist&quot;) else { return nil }</code></pre>



<p>Always make sure to type the file name and its extension correctly when using the above method; a typo error is enough to make you lose time and wonder why the file cannot be found even though it exists in the project. If the file is found, its URL is assigned to the <code>url</code> property.</p>



<p>Next, we&#x2019;ll load the file contents to a <em>Data</em> NSObject:</p>



<pre class="wp-block-code"><code>do {
    let data = try Data(contentsOf: url)
} catch {
    print(error.localizedDescription)
    return nil
}</code></pre>



<p>Initializing a <code>Data</code> object as shown above can throw an exception, so including it in a <code>do-catch</code> statement is necessary. In case the file cannot be read and the <code>data</code> property to be initialized, then we print the description of the error occurred, and we return <code>nil</code>.</p>



<p>Since the above <code>data</code> object was created by using the contents of a <em>property list file</em>, we&#x2019;ll decode it and convert it to an array of String elements with the help of the <a href="https://developer.apple.com/documentation/foundation/propertylistserialization?ref=appcoda.com"><em>PropertyListSerialization</em></a> class; it allows to encode to and decode from property list objects. If you&#x2019;re familiar to the <em>JSONSerialization</em> class, then this one is the equivalent for property lists, not JSON objects.</p>



<p>Still inside the <code>do-catch</code> statement, let&#x2019;s convert the loaded property list data into an array as shown right below:</p>



<pre class="wp-block-code"><code>let productIDs = try PropertyListSerialization.propertyList(from: data, options: .mutableContainersAndLeaves, format: nil) as? [String] ?? []</code></pre>



<p>In case it&#x2019;s not possible to convert to a collection of String values, then we just assign an empty array to <code>productIDs</code>.</p>



<p>Finally, we need to return it:</p>



<pre class="wp-block-code"><code>return productIDs</code></pre>



<p>Here&#x2019;s the whole method:</p>



<pre class="wp-block-code"><code>fileprivate func getProductIDs() -&gt; [String]? {
    guard let url = Bundle.main.url(forResource: &quot;IAP_ProductIDs&quot;, withExtension: &quot;plist&quot;) else { return nil }
    do {
        let data = try Data(contentsOf: url)
        let productIDs = try PropertyListSerialization.propertyList(from: data, options: .mutableContainersAndLeaves, format: nil) as? [String] ?? []
        return productIDs
    } catch {
        print(error.localizedDescription)
        return nil
    }
}</code></pre>



<h2 class="wp-block-heading">Requesting App Store For Available IAP Products</h2>



<p>Making <code>IAPManager</code> capable of loading the product IDs, the next step is to fetch all available products offered for purchase from the App Store. This action will return a collection of <code>SKProduct</code> objects, where each one describes an in-app purchase and contains its details as it was configured on the App Store.</p>



<p>We&#x2019;ll start by defining a new method:</p>



<pre class="wp-block-code"><code>func getProducts(withHandler productsReceiveHandler: @escaping (_ result: Result&lt;[SKProduct], IAPManagerError&gt;) -&gt; Void) {

}</code></pre>



<p>Let&#x2019;s talk a bit about the parameter of this method, and let me start with a question: Are you aware of the <a href="https://developer.apple.com/documentation/swift/result?ref=appcoda.com"><strong>Result</strong></a> type that was first-introduced in Swift 5? Citing the official documentation:</p>



<p><em>A value that represents either a success or a failure, including an associated value in each case.</em></p>



<p>In simple words, this type makes it easy to return the outcome of an operation and to indicate whether it was successful or not. On success, it&#x2019;s possible to carry any necessary custom data; on failure it carries the error that caused the operation to fail.</p>



<p>In our case, our <code>Result</code> value will carry the <em>collection of fetched products from the App Store</em> if we get them successfully, and a custom error type (<code>IAPManagerError</code>) on failure.</p>



<p>Fetching IAP products from the App Store is an asynchronous process. That means that the above method <em>cannot return the products fetching result instantly</em>. So, the parameter of the method has to be a <em>closure</em> (or a <em>callback handler</em> in other words) which will be called when <code>StoreKit</code> notifies our class that has got a response from the App Store. The parameter of that closure is the <code>Result</code> value as shown in the method definition above.</p>



<p>The above borns a new requirement now: To declare a property in the <code>IAPManager</code> class which will keep a reference to the handler (closure) even when the execution of the <code>getProducts(withHandler:)</code> method is finished. Go to the beginning of the class in the properties declaration area and add the following:</p>



<pre class="wp-block-code"><code>var onReceiveProductsHandler: ((Result&lt;[SKProduct], IAPManagerError&gt;) -&gt; Void)?</code></pre>



<p>Back to the <code>getProducts(withHandler:)</code> method now. We start implementing it by assigning the <code>productsReceiveHandler</code> parameter value to the <code>onReceiveProductsHandler</code> property so we can call it at any time later in the future:</p>



<pre class="wp-block-code"><code>onReceiveProductsHandler = productsReceiveHandler</code></pre>



<p>Next, let&#x2019;s get the collection of the identifiers for the products that we want to fetch data for. For this purpose, we&#x2019;ll make use of the <code>getProductIDs()</code> method we implemented earlier:</p>



<pre class="wp-block-code"><code>guard let productIDs = getProductIDs() else {
    productsReceiveHandler(.failure(.noProductIDsFound))
    return
}</code></pre>



<p>Remember that it&#x2019;s possible for the above to return <code>nil</code>. If that happens, then the wanted product identifiers could not be read for some reason and we should return from this method immediately. However, it&#x2019;s necessary to notify the caller of the class about the error that occurred. We call the <code>productsReceiveHandler</code> handler and we pass a <code>Result</code> type with a <em>failure</em> indicating the exact error happened.</p>



<p><em>Note: If you find yourself being uncomfortable by the syntax of the <code>Result</code> type, then I&#x2019;d recommend to search for more usage examples on the Internet, as well as to play with it in a playground until you master it.</em></p>



<p>Continuing to the implementation, let&#x2019;s initialize a <em>products request</em> for the App Store:</p>



<pre class="wp-block-code"><code>let request = SKProductsRequest(productIdentifiers: Set(productIDs))</code></pre>



<p>The initializer shown above awaits for a <code>Set</code> of product identifiers, not an array. That&#x2019;s why we initialize a new <code>Set</code> using the <code>productIDs</code> array.</p>



<p>As mentioned already, requesting the App Store is not a synchronous operation. The result of it, meaning the response from the App Store, is available through a couple of methods provided by the <code>SKProductsRequestDelegate</code> and <code>SKRequestDelegate</code> protocols. <code>IAPManager</code> class will adopt them, but first it must be set as the request&#x2019;s delegate:</p>



<pre class="wp-block-code"><code>request.delegate = self</code></pre>



<p>We are now ready to make the request:</p>



<pre class="wp-block-code"><code>request.start()</code></pre>



<p>The <code>getProducts(withHandler:)</code> method is a quite important one, and even though it&#x2019;s small, it contains vital steps for making in-app purchases possible. Here it is all together:</p>



<pre class="wp-block-code"><code>func getProducts(withHandler productsReceiveHandler: @escaping (_ result: Result&lt;[SKProduct], IAPManagerError&gt;) -&gt; Void) {
    // Keep the handler (closure) that will be called when requesting for
    // products on the App Store is finished.
    onReceiveProductsHandler = productsReceiveHandler

    // Get the product identifiers.
    guard let productIDs = getProductIDs() else {
        productsReceiveHandler(.failure(.noProductIDsFound))
        return
    }

    // Initialize a product request.
    let request = SKProductsRequest(productIdentifiers: Set(productIDs))

    // Set self as the its delegate.
    request.delegate = self

    // Make the request.
    request.start()
}</code></pre>



<h2 class="wp-block-heading">Handling App Store Response</h2>



<p>Right above we set the <code>IAPManager</code> class as the delegate of the <code>SKProductsRequest</code> object (the request). Now, it&#x2019;s mandatory to adopt the <code>SKProductsRequestDelegate</code> protocol and implement at least one required method.</p>



<p>Go after the closing curly bracket of the <code>IAPManager</code> class, and add the following extension:</p>



<pre class="wp-block-code"><code>extension IAPManager: SKProductsRequestDelegate {

}</code></pre>



<p>In it we&#x2019;ll implement the following method which gets called when the App Store sends back a response to the original request:</p>



<pre class="wp-block-code"><code>func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {

}</code></pre>



<p>The first parameter value regards the request that triggered the response. The second (the <code>response</code>) is what we really care about here, as it contains a collection of <code>SKProduct</code> objects; the available content for purchase. Each product contained in the response matches to a single product identifier in the list of identifiers existing in our property list file.</p>



<p>Going into the logic that we&#x2019;ll apply here, at first we&#x2019;ll get the collection of products:</p>



<pre class="wp-block-code"><code>let products = response.products</code></pre>



<p>Then we&#x2019;ll check if there are any products returned or not. If so, we&#x2019;ll call the <code>onReceiveProductsHandler</code> and we&#x2019;ll pass a <code>Result</code> value indicating a success and supplying it with the array of products:</p>



<pre class="wp-block-code"><code>if products.count &gt; 0 {
    onReceiveProductsHandler?(.success(products))
} else {

}</code></pre>



<p>Among others, the above illustrates how a <code>Result</code> value with the case of success is being constructed.</p>



<p>In case there are no products returned, we&#x2019;ll call the <code>onReceiveProductsHandler</code> once again, but this time the <code>Result</code> value will indicate an error, and we&#x2019;ll pass the <code>noProductsFound</code> custom error as its associated value:</p>



<pre class="wp-block-code"><code>onReceiveProductsHandler?(.failure(.noProductsFound))</code></pre>



<p>Even though finding no products is not necessarily an error (when, for example, there are no IAP entries on App Store or the given product identifiers do not match to any IAPs), treating it the way shown above ensures that the two cases of having and not having products will be handled separately by the caller of this class.</p>



<p>Here&#x2019;s the entire method:</p>



<pre class="wp-block-code"><code>func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
    // Get the available products contained in the response.
    let products = response.products

    // Check if there are any products available.
    if products.count &gt; 0 {
        // Call the following handler passing the received products.
        onReceiveProductsHandler?(.success(products))
    } else {
        // No products were found.
        onReceiveProductsHandler?(.failure(.noProductsFound))
    }
}</code></pre>



<p><em>Note: The <code>response</code> object provides a property called <code>invalidProductIdentifiers</code>. It&#x2019;s a collection of identifiers regarding products that are not valid to be purchased. Although we do not use it here, keep it in mind in case you ever need it.</em></p>



<p>What the above method does not do is to let us know if the request failed for some reason. We can deal with that by implementing another delegate method:</p>



<pre class="wp-block-code"><code>func request(_ request: SKRequest, didFailWithError error: Error) {

}</code></pre>



<p>Regardless of the error that caused the request to fail, it&#x2019;s necessary to let the <code>IAPManager</code> caller know about it. For one more time we&#x2019;re going to call the <code>onReceiveProductsHandler</code> closure passing the <code>productRequestFailed</code> custom error.</p>



<pre class="wp-block-code"><code>onReceiveProductsHandler?(.failure(.productRequestFailed))</code></pre>



<p>Finally, there&#x2019;s one more delegate method which can be optionally implemented:</p>



<pre class="wp-block-code"><code>func requestDidFinish(_ request: SKRequest) {

}</code></pre>



<p>We won&#x2019;t use it here, but be aware of it in case there&#x2019;s any additional custom logic you want to add.</p>



<h2 class="wp-block-heading">Getting Product&#x2019;s Price As A String</h2>



<p>In the next part we&#x2019;re going to have a first taste about everything we&#x2019;ve done so far, but before that it&#x2019;s necessary to implement a small assistive, yet necessary method in the <code>IAPManager</code> class. Its purpose is to <em>return a product&#x2019;s price as a formatted currency string</em>. The implementation shown right next is taken as-is from Apple&#x2019;s documentation but it&#x2019;s not hard to understand it:</p>



<pre class="wp-block-code"><code>func getPriceFormatted(for product: SKProduct) -&gt; String? {
    let formatter = NumberFormatter()
    formatter.numberStyle = .currency
    formatter.locale = product.priceLocale
    return formatter.string(from: product.price)
}</code></pre>



<p>Notice that the string is created based on the product&#x2019;s localized price value which is taken by accessing the <code>priceLocale</code> property.</p>



<h2 class="wp-block-heading">Testing What Is Built So Far</h2>



<p>Let&#x2019;s take a small break from building the <code>IAPManager</code> class now, and let&#x2019;s make a few updates to other parts of the app so we can run it and test what we&#x2019;ve done so far. There are two things that we&#x2019;ll do here:</p>



<ol><li>We&#x2019;ll fetch the available in-app purchases from the App Store (the products).</li><li>We&#x2019;ll display product information while trying to initiate a buy process.</li></ol>



<p><em>Note: Since the goal of this post is to focus on the creation of a reusable component to perform in-app purchases, I&#x2019;ll save us some time by being less thorough when presenting missing parts of the app which are not related directly to the <code>IAPManager</code> class. Please take your time and have a good look at the project if you need so.</em></p>



<h3 class="wp-block-heading">Fetching IAP Products</h3>



<p>Before users are able to make any in-app purchase, the app must fetch all information about available IAPs from the App Store. There&#x2019;s no rule when exactly apps should do that, it always depends on each specific app itself. Sometimes it&#x2019;s suitable to fetch products right before an in-app purchase is started. Some other times it&#x2019;s better to fetch them right after the app has launched.</p>



<p>In this demo application, and given the fact that we have one view controller only, we&#x2019;ll fetch the available IAP products right after the view of the view controller has appeared and it&#x2019;s ready to be used. If you check the <code>viewDidAppear(_:)</code> method in the <em>ViewController.swift</em> file, you&#x2019;ll see that it calls the <code>viewDidSetup()</code> method of the <code>ViewModel</code> instance; that is place where we&#x2019;ll initiate the product fetching.</p>



<p>Open the <em>ViewModel.swift</em> file and locate the <code>viewDidSetup()</code> method. When there are no products fetched recently by the App Store, no in-app purchase process can start, so users have to wait a bit. Let&#x2019;s do that, and let&#x2019;s trigger the appearance of <em>an overlay view with an activity indicator in it</em> while the app &#x201C;talks&#x201D; to the App Store and requests for any in-app purchases:</p>



<pre class="wp-block-code"><code>func viewDidSetup() {
    delegate?.willStartLongProcess()
}</code></pre>



<p>Now we can use the <code>getProducts(withHandler:)</code> we implemented earlier in the <code>IAPManager</code> class. Remember that <code>IAPManager</code> is a <em>singleton</em> class therefore we access the method through its <code>shared</code> instance:</p>



<pre class="wp-block-code"><code>IAPManager.shared.getProducts { (result) in

}</code></pre>



<p>We can remove the overlay view shown in the app when the fetching process is finished and the above closure gets called. Just remember to do that on the <em>main thread</em>.</p>



<pre class="wp-block-code"><code>DispatchQueue.main.async {
    self.delegate?.didFinishLongProcess()
}</code></pre>



<p>Let&#x2019;s handle the <code>result</code> now. If it&#x2019;s a success, then it&#x2019;ll contain the fetched IAP products; if it&#x2019;s a failure it&#x2019;ll carry the error that caused it. In the first case we keep the fetched products in the <code>products</code> property of our <code>model</code>; in the second we trigger the appearance of an alert that will display the <em>localized description</em> of the returned error:</p>



<pre class="wp-block-code"><code>switch result {
    case .success(let products): self.model.products = products
    case .failure(let error): self.delegate?.showIAPRelatedError(error)
}</code></pre>



<p>Find the implementation of the <code>showIAPRelatedError(_:)</code> delegate method in the <em>ViewController.swift</em> file to find out how the error is being displayed.</p>



<p>Run the app now if you want (either in Simulator or on a device) and look the overlay view with the spinner appearing while the app is fetching the in-app purchase information from the App Store. If it just disappears after a few moments, then products have been successfully fetched and kept by the app. If any error occurs, you&#x2019;ll see an alert showing up with the error description.</p>



<p>Here&#x2019;s the entire method we just implemented:</p>



<pre class="wp-block-code"><code>func viewDidSetup() {
    delegate?.willStartLongProcess()

    IAPManager.shared.getProducts { (result) in

        DispatchQueue.main.async {
            self.delegate?.didFinishLongProcess()

            switch result {
            case .success(let products): self.model.products = products;
            case .failure(let error): self.delegate?.showIAPRelatedError(error)
            }
        }
    }
}</code></pre>



<p>Note: The way you&#x2019;ll temporarily keep fetched IAP products in your app is totally up to you. Here I chose to create the <code>products</code> property in the <code>Model</code> class, which is an array of <code>SKProduct</code> elements.</p>



<h3 class="wp-block-heading">Displaying Product Information</h3>



<p>By having the available in-app purchase products at the app&#x2019;s disposal, we can use them for presenting certain information to users when a purchase process is about to start. To be specific, we&#x2019;ll be displaying the following for each product a user wants to purchase:</p>



<ul><li>The localized title.</li><li>The localized description.</li><li>The price.</li></ul>



<p>Remember that all of them have been set on the App Store. And here&#x2019;s something to avoid: <em>Do not hardcode any title, description or price into the app; all these can change at any time if you edit your in-app purchase records on the App Store</em>.</p>



<p>Let&#x2019;s focus on our demo app again now. We will initiate a purchase process when a user taps on a cell and any of the following is true:</p>



<ul><li>The first cell is tapped and there are no extra lives available.</li><li>The second cell is tapped and there are no super powers available.</li><li>The third cell is tapped (Note: Third cell won&#x2019;t be visible after unlocking all maps by buying the matching product; it regards a <em>non-consumable</em> product).</li></ul>



<p>This logic is already applied in the <code>tableView(_:didSelectRowAt:)</code> table view delegate method in the <em>ViewController.swift</em> file. Go there and take a look now. When any of the above conditions is true, the <code>getProductForItem(at:)</code> method of the <code>ViewModel</code> is called in order to return the matching product to the tapped cell. That product is given as an argument to the <code>showAlert(for:)</code> method defined in the <code>ViewController</code> class.</p>



<p>The purpose of the <code>showAlert(for:)</code> method is to display an alert controller which will contain all the product details mentioned above right before an in-app purchase is made. It actually displays an alert that asks users if they want to continue with the purchase of the described item.</p>



<p><em>Note: I would recommend against of using a default alert controller for displaying a product&#x2019;s information, unless your app is implements a really basic UI. You&#x2019;d better describe products in custom designed views that match to the look and feel of your app.</em></p>



<p>Locate the <code>showAlert(for:)</code> method in the <em>ViewController.swift</em> file. We&#x2019;ll start implementing it by getting the <em>localized price</em> of the product given as an argument:</p>



<pre class="wp-block-code"><code>func showAlert(for product: SKProduct) {
    guard let price = IAPManager.shared.getPriceFormatted(for: product) else { return }
}</code></pre>



<p>Let&#x2019;s initialize an alert controller now. We&#x2019;ll display the product&#x2019;s title as the alert&#x2019;s title, and the product&#x2019;s description as the alert&#x2019;s message:</p>



<pre class="wp-block-code"><code>let alertController = UIAlertController(title: product.localizedTitle,
                                        message: product.localizedDescription,
                                        preferredStyle: .alert)</code></pre>



<p>The product&#x2019;s price will be used as part of the title of an alert action that will prompt users to buy the item. Here it is:</p>



<pre class="wp-block-code"><code>alertController.addAction(UIAlertAction(title: &quot;Buy now for \(price)&quot;, style: .default, handler: { (_) in
    // TODO: Initiate Purchase!
}))</code></pre>



<p>The button&#x2019;s title will say something: &#x201C;Buy now for $0.49&#x201D;. When users tap on it, the actual purchase process will be initiated, but that&#x2019;s for later. For now we just leave a &#x201C;TODO&#x201D; comment.</p>



<p>Finally, let&#x2019;s add a <em>cancel</em> action to the alert, and let&#x2019;s present it:</p>



<pre class="wp-block-code"><code>alertController.addAction(UIAlertAction(title: &quot;Cancel&quot;, style: .cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)</code></pre>



<p>Here&#x2019;s the entire method:</p>



<pre class="wp-block-code"><code>func showAlert(for product: SKProduct) {
    guard let price = IAPManager.shared.getPriceFormatted(for: product) else { return }
    let alertController = UIAlertController(title: product.localizedTitle,
                                            message: product.localizedDescription,
                                            preferredStyle: .alert)

    alertController.addAction(UIAlertAction(title: &quot;Buy now for \(price)&quot;, style: .default, handler: { (_) in
        // TODO: Initiate Purchase!
    }))

    alertController.addAction(UIAlertAction(title: &quot;Cancel&quot;, style: .cancel, handler: nil))
    self.present(alertController, animated: true, completion: nil)
}</code></pre>



<p>Run the app now and tap on any cell. You should see the alert we just created is showing up and describing the selected product! Of course no purchase can take place now, and that&#x2019;s something that we&#x2019;re going to change right now!</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="571" height="1024" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_27_product_description-571x1024.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17356" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_27_product_description-571x1024.png 571w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_27_product_description-200x359.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_27_product_description-167x300.png 167w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_27_product_description-400x718.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_27_product_description-50x90.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_27_product_description.png 584w" sizes="(max-width: 571px) 100vw, 571px"></figure></div>



<h2 class="wp-block-heading">Implementing Purchases</h2>



<p>In programming level, a purchase is a transaction (aka a <code>SKPaymentTransaction</code> object), and responsible for managing transactions is a class called <em>SKPaymentQueue</em>. The payment queue is the one which communicates with the App Store and handles all the payment process. It&#x2019;s also responsible for presenting the built-in UI that appears when performing purchases.</p>



<p>Every app that wants to offer in-app purchases is required <em>to add a payment transaction observer to the queue (a <code>SKPaymentTransactionObserver</code> object)</em> so it&#x2019;s capable of catching any updates regarding a purchase. As you understand, making purchases is an asynchronous process just like fetching the products information from the App Store. The outcome of a transaction should always become absolutely clear to users, regardless of whether it was successful or not.</p>



<h3 class="wp-block-heading">Observing The Payment Queue</h3>



<p>So, with that new information in mind, let&#x2019;s go back to the <em>IAPManager.swift</em> file where we&#x2019;ll implement two new small methods. With them we&#x2019;ll be adding and removing a payment transaction observer to the payment queue respectively:</p>



<pre class="wp-block-code"><code>func startObserving() {
    SKPaymentQueue.default().add(self)
}


func stopObserving() {
    SKPaymentQueue.default().remove(self)
}</code></pre>



<p>Just implementing the above two is not enough. It&#x2019;s also necessary to call them appropriately so the app can start and stop observing for payment transaction updates as needed.</p>



<p>Open the <em>AppDelegate.swift</em> file. In the <code>application(_:didFinishLaunchingWithOptions:)</code> method make call to <code>startObserving()</code> so the app starts observing each time is launched:</p>



<pre class="wp-block-code"><code>func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&gt; Bool {
    IAPManager.shared.startObserving()
    return true
}</code></pre>



<p>Next, implement the <code>applicationWillTerminate(_:)</code> to stop observing:</p>



<pre class="wp-block-code"><code>func applicationWillTerminate(_ application: UIApplication) {
    IAPManager.shared.stopObserving()
}</code></pre>



<p>That&#x2019;s it. The app is now capable of watching properly for updates in the payment queue, and we are ready to move forward and make it possible to create new transactions (meaning to make new purchases), as well as to handle any transaction related updates coming from the App Store.</p>



<p><em>Note: Don&#x2019;t be bothered by the couple of errors currently shown by Xcode; they&#x2019;ll be fixed soon.</em></p>



<h3 class="wp-block-heading">Checking For IAP Eligible Device</h3>



<p>Before an app triggers a purchase process, it&#x2019;s important to know whether in-app purchases are actually <em>allowed or supported</em> on a device. It&#x2019;s possible, for example, that parents have turned off IAPs through the device settings. That&#x2019;s a state that apps must always check for and notify users accordingly.</p>



<p>The information of whether in-app purchases can be made is something that&#x2019;s taken from the payment queue once again. Go to the <em>IAPManager.swift</em> file and implement the following method:</p>



<pre class="wp-block-code"><code>func canMakePayments() -&gt; Bool {
    return SKPaymentQueue.canMakePayments()
}</code></pre>



<p>As you see, it&#x2019;s as simple as that. We will call <code>canMakePayments()</code> method later on, when we&#x2019;ll keep adding the missing parts from the demo app that will make purchases possible.</p>



<h3 class="wp-block-heading">Making Purchases</h3>



<p>With the payment queue being observed and with the ability to know whether a device can actually make payments or not, let&#x2019;s go to the implementation of a new method that triggers a new purchase:</p>



<pre class="wp-block-code"><code>func buy(product: SKProduct, withHandler handler: @escaping ((_ result: Result&lt;Bool, Error&gt;) -&gt; Void)) {
    let payment = SKPayment(product: product)
    SKPaymentQueue.default().add(payment)

    // Keep the completion handler.
    onBuyProductHandler = handler
}</code></pre>



<p>This method accepts two arguments:</p>



<ol><li>The first one is the actual product (a <code>SKProduct</code> object) that is about to be purchased.</li><li>The second parameter is a callback handler ( a closure) similar to the one we met in the <code>getProducts(withHandler:)</code> method. It has a <code>Result</code> type as a parameter with a boolean value as the associated value for the success case, and an error object as the associated value for the failure case. This callback handler is necessary because making a payment is an asynchronous operation; it&#x2019;ll be called when the payment process is finished.</li></ol>



<p>Inside the method now, we initialize a payment object (<code>SKPayment</code>) using the given product. Then, we add the payment object to the payment queue and we&#x2019;re done! Once a new payment object is added to the payment queue, things will start working without any other action on our behalf, so we just have to wait for the entire process to come to its end.</p>



<p>The callback handler that is given as an argument to this method should be kept in a class property, so it&#x2019;s available when the method&#x2019;s execution is finished. This is what&#x2019;s happening in the last line above; the <code>handler</code> parameter value is assigned to the <code>onBuyProductHandler</code>. However, the second one does not exist in the <code>IAPManager</code> class yet.</p>



<p>Go to the properties declaration area of the class and add the following line:</p>



<pre class="wp-block-code"><code>var onBuyProductHandler: ((Result&lt;Bool, Error&gt;) -&gt; Void)?</code></pre>



<h3 class="wp-block-heading">Handling Transaction Results</h3>



<p>Now that we made it possible to make a payment, let&#x2019;s handle the results of a transaction. For this purpose, we need to adopt the <code>SKPaymentTransactionObserver</code> protocol and implement a required method.</p>



<p>Go after the closing curly bracket of the <code>IAPManager</code> class once again, and add one more extension:</p>



<pre class="wp-block-code"><code>extension IAPManager: SKPaymentTransactionObserver {

}</code></pre>



<p>In it we&#x2019;ll implement the following method:</p>



<pre class="wp-block-code"><code>extension IAPManager: SKPaymentTransactionObserver {
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {

    }
}</code></pre>



<p>This method is called when the state of a transaction changes. The second parameter value, <code>transactions</code>, is an array of <code>SKPaymentTransaction</code> objects as multiple transactions can be running at the same time. We&#x2019;ll start with that and we&#x2019;ll go through each transaction:</p>



<pre class="wp-block-code"><code>transactions.forEach { (transaction) in

}</code></pre>



<p>Next, we&#x2019;ll add a <code>switch</code> statement which we&#x2019;ll use to examine the various states of each transaction:</p>



<pre class="wp-block-code"><code>switch transaction.transactionState {
case .purchased:

case .restored:

case .failed:

case .deferred, .purchasing: break
@unknown default: break
}</code></pre>



<p>What we are really interested about is the first three cases:</p>



<ol><li><code>purchased</code>: When a payment is finished and the product has been purchased.</li><li><code>restored</code>: When a previously purchased item has been restored from the App Store.</li><li><code>failed</code>: When a transaction fails.</li></ol>



<p>In the first case where a purchase is successful, we&#x2019;ll call the <code>onBuyProductHandler</code> closure passing <code>true</code> as the value of the result object. This will notify the <code>IAPManager</code>&#x2018;s caller about the successful outcome. On top of that, there&#x2019;s one more action that&#x2019;s mandatory to be done; to indicate to the payment queue that it can now consider the transaction as finished.</p>



<pre class="wp-block-code"><code>case .purchased:
    onBuyProductHandler?(.success(true))
    SKPaymentQueue.default().finishTransaction(transaction)</code></pre>



<p>Actually, the last line is something we&#x2019;ll also do in the next cases too.</p>



<p>We&#x2019;ll postpone the <code>restored</code> case for a bit later. For now add this:</p>



<pre class="wp-block-code"><code>case .restored: break</code></pre>



<p>In the <code>failed</code> case, we&#x2019;ll check at first if the transaction&#x2019;s <code>error</code> object is <code>nil</code> or not. A transaction&#x2019;s error is a <code>SKError</code> object and it has a specific code that describes the error. There&#x2019;s a special one called <code>paymentCancelled</code> and it&#x2019;s happening when a user cancels a purchase right before the actual payment is done. If this is the case, then we&#x2019;ll pass a failure value to the result with the custom <code>IAPManagerError.paymentWasCancelled</code> error. If not, then we&#x2019;ll pass failure with the actual error that took place. That way we&#x2019;ll make it easy for the app to know whether the payment failed because of the user or not.</p>



<pre class="wp-block-code"><code>case .failed:
if let error = transaction.error as? SKError {
    if error.code != .paymentCancelled {
        onBuyProductHandler?(.failure(error))
    } else {
        onBuyProductHandler?(.failure(IAPManagerError.paymentWasCancelled))
    }
    print(&quot;IAP Error:&quot;, error.localizedDescription)
}
SKPaymentQueue.default().finishTransaction(transaction)</code></pre>



<p>Implementing the capability to make in-app purchases is now complete. Time to try it out!</p>



<h2 class="wp-block-heading">Enable App To Make Purhases</h2>



<p>Open the <em>ViewModel.swift</em> file where you&#x2019;ll find a defined, yet still empty method called <code>purchase(product:)</code>. In this one we&#x2019;ll add the missing logic which will make use of what we just did in the previous parts and ultimately make payments come true for our demo app.</p>



<p>As you can see the returned value from the method is a boolean one. The only case where this method will return <code>false</code> is going to be when no payments can be made on a specific device. Otherwise it&#x2019;ll trigger the new payment using the product provided as an argument and it&#x2019;ll return <code>true</code>. Let&#x2019;s see that:</p>



<pre class="wp-block-code"><code>func purchase(product: SKProduct) -&gt; Bool {
    if !IAPManager.shared.canMakePayments() {
        return false
    } else {

    }

    return true
}</code></pre>



<p>Here&#x2019;s the place where we make use of the <code>canMakePayments()</code> method which we implemented earlier.</p>



<p>Focusing on the <code>else</code> case now, we&#x2019;ll indicate to the View part of our MVVM based app that a long process is about to start. This will make the overlay view with the activity indicator appear:</p>



<pre class="wp-block-code"><code>delegate?.willStartLongProcess()</code></pre>



<p>Let&#x2019;s trigger the purchase:</p>



<pre class="wp-block-code"><code>IAPManager.shared.buy(product: product) { (result) in

}</code></pre>



<p>We&#x2019;re calling the <code>buy(product:)</code> method of the <code>IAPManager</code> class passing the <code>product</code> parameter value given to the <code>purchase(product:)</code> as its argument. The above closure is the one assigned to the <code>onBuyProductHandler</code> property in the <code>IAPManager</code> class. It&#x2019;ll be called back when the purchase will have either finished successfully or not; it&#x2019;s the <code>result</code> value to tell that.</p>



<p>Since the purchase is an asynchronous operation taking place on the background, whatever we&#x2019;ll do in the above closure must be done on the main thread. After all, we&#x2019;re going to initiate UI changes and that&#x2019;s something that cannot be done using a background thread.</p>



<pre class="wp-block-code"><code>DispatchQueue.main.async {
    self.delegate?.didFinishLongProcess()

    switch result {
    case .success(_): self.updateGameDataWithPurchasedProduct(product)
    case .failure(let error): self.delegate?.showIAPRelatedError(error)
    }
}</code></pre>



<p>By calling the <code>didFinishLongProcess()</code> delegate method we make the overlay view disappear. Next, we examine the <code>result</code> value. On success we call the <code>updateGameDataWithPurchasedProduct(_:)</code> method which is already implemented in the <code>ViewModel</code> class. This is the method which, depending on the purchased product, will add extra lives or extra powers to our fake game (consumable products), or it will mark all maps as unlocked (non-consumable). Go and take a look at <code>updateGameDataWithPurchasedProduct(_:)</code>.</p>



<p>If the purchase fails, then we let our view controller know about that and therefore show the error message through the <code>showIAPRelatedError(_:)</code> delegate method. Note that the way a purchase&#x2019;s results will be handled is totally depending on the app that&#x2019;s being developed, the logic applied to it, the design, and so on. So, what you see above is something that has a meaning to this demo app only. However, this doesn&#x2019;t mean you cannot act similarly in your own apps; feel free to use this method as a guide.</p>



<p>Here&#x2019;s the <code>purchase(product:)</code> all together:</p>



<pre class="wp-block-code"><code>func purchase(product: SKProduct) -&gt; Bool {
    if !IAPManager.shared.canMakePayments() {
        return false
    } else {
        delegate?.willStartLongProcess()
        IAPManager.shared.buy(product: product) { (result) in
            DispatchQueue.main.async {
                self.delegate?.didFinishLongProcess()

                switch result {
                case .success(_): self.updateGameDataWithPurchasedProduct(product)
                case .failure(let error): self.delegate?.showIAPRelatedError(error)
                }
            }
        }
        return true
    }
}</code></pre>



<p>Open the <em>ViewController.swift</em> file now and search for this comment: <em>// TODO: Initiate Purchase!</em>. You should find it in the action of the alert controller that displays the product information that is about to be purchased (<code>showAlert(for:)</code> method). Replace that comment and update the action as shown next:</p>



<pre class="wp-block-code"><code>alertController.addAction(UIAlertAction(title: &quot;Buy now for \(price)&quot;, style: .default, handler: { (_) in

    if !self.viewModel.purchase(product: product) {
        self.showSingleAlert(withMessage: &quot;In-App Purchases are not allowed in this device.&quot;)
    }

}))</code></pre>



<p>If the <code>purchase(product:)</code> returns <code>false</code>, then the device cannot make payments and we&#x2019;re showing an alert to let users know about that. Otherwise, things will flow as we built it earlier.</p>



<h2 class="wp-block-heading">Testing In-App Purchases</h2>



<p>In order to test in-app purchases <em>you&#x2019;ll need a real device</em>. Payments cannot be done using a Simulator. However <strong>before you begin</strong> make sure to <strong>sign out from your iCloud account</strong> if you&#x2019;re already connected in your device. We want all tests to take place on a sandboxed environment.</p>



<p>After you sign out, <em>do not connect to iCloud using a test account</em>. This is not the place to do it! You&#x2019;ll be asked to sign in when you initiate a purchase process. However, in case you want to set the test account you&#x2019;ll use in advance, or if you want to change the test user later, then:</p>



<ul><li>Open Settings.</li><li>Go to <strong>iTunes &amp; App Store</strong>.</li><li>Scroll to bottom. There&#x2019;s a section called <strong>Sandbox Account</strong>. Tap on <em>Sign-In</em> and provide the test user credentials.</li></ul>



<p><em>Note: Do not provide a real Apple ID here!</em></p>



<p>In addition to the above, you might want to disallow in-app purchases in your device so you can test that case too. In order to do that, go to Settings and then:</p>



<ul><li><em>Screen Time</em></li><li><em>Content &amp; Privacy Restrictions</em></li><li><em>iTunes &amp; App Store Purchases</em></li><li><em>In-app Purchases</em></li><li>Select <em>Don&#x2019;t Allow</em></li></ul>



<p>To enable IAPs again, follow the same steps but at the end select <em>Allow</em>.</p>



<p>Now that you know how to assign or change a test user, and how to turn on and off in-app purchases, compile the app and let it run on your device. Tap on any fake product you want to buy. For example, tap on the extra lives cell and then on the <em>Buy</em> button. Provide the test user&#x2019;s credentials and confirm the payment. Once it&#x2019;s successfully done, you&#x2019;ll see that you have three available lives which you can <em>consume</em> by tapping on the cell. When you&#x2019;re out of lives, you&#x2019;ll be asked to buy again.</p>



<p><em>Note: Pay attention to the system alerts that are showing up. While confirming the purchase you should be seeing the <strong>[Environment: Sandbox]</strong> indication. If you don&#x2019;t see that, then you&#x2019;re not making the purchase using a test account and you should not proceed until you change that.</em></p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="577" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-1024x577.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17357" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-1024x577.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-200x113.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-532x300.png 532w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-768x433.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-1680x947.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-1240x699.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-860x485.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-680x383.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-400x225.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_3_purchase_process-1-50x28.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>In case you start the purchase but you cancel it before confirming the buy, here&#x2019;s what you&#x2019;ll see:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="576" height="1024" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-576x1024.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17358" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-576x1024.png 576w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-200x356.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-169x300.png 169w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-768x1365.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-1240x2204.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-860x1529.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-680x1209.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-400x711.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment-50x89.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_29_cancelled_payment.png 1242w" sizes="(max-width: 576px) 100vw, 576px"></figure>



<p>Note that you can keep buying extra lives and super powers for as long as you want when running out of them. However, unlocking all maps can be purchased just once; it&#x2019;s a non-consumable product, and when you do so the last cell will no longer be appearing on the table view.</p>



<h2 class="wp-block-heading">Restoring Purchases</h2>



<p>Even though we made it possible to perform in-app purchases and buy digital products through our app, there&#x2019;s still one thing missing. That is the option to <em>restore previously purchased non-consumable products</em>.</p>



<p>When users pay once for a non-consumable product (like unlocking all maps in our demo app), they should never be asked to pay for it again. However, they should be able to get their purchase back when they install the app on a different device or when they re-install on the same one. Apple <em>requires</em> a restore button to exist in our UI which should be clearly visible and understandable by users. Without the option to restore, get ready to see your app being rejected from the App Store.</p>



<p>Thankfully, App Store keeps record of purchases made on non-consumable products and it will prevent users from paying again for something they&#x2019;ve already bought. That means that even if someone tries to buy again a non-consumable product will fail; Once <code>StoreKit</code> and the payment queue get the information from the App Store that there is a previous payment, the new process will be considered as a restore and the user won&#x2019;t be charged for it.</p>



<p>Restoring purchases is something we&#x2019;re still missing in the <code>IAPManager</code> class, so let&#x2019;s take care of it now. Open the <em>IAPManager.swift</em> file and add the following new method:</p>



<pre class="wp-block-code"><code>func restorePurchases(withHandler handler: @escaping ((_ result: Result&lt;Bool, Error&gt;) -&gt; Void)) {
    onBuyProductHandler = handler
    totalRestoredPurchases = 0
    SKPaymentQueue.default().restoreCompletedTransactions()
}</code></pre>



<p>Let&#x2019;s start with the parameter value. Once again it&#x2019;s the (familiar) callback handler we also had in the <code>buy(product:)</code> method too, so we assign it to the <code>onBuyProductHandler</code> class property for future use.</p>



<p>You might be wondering what the <code>totalRestoredPurchases</code> variable is all about. When having restorable products, it&#x2019;s good to know whether all of them were restored or not, and by using such a <em>counter</em> you can easily verify it. You&#x2019;ll see how it&#x2019;ll be used in a while, but first, declare it in the <code>IAPManager</code> class along with the other class properties:</p>



<pre class="wp-block-code"><code>var totalRestoredPurchases = 0</code></pre>



<p>Finally, by calling the <code>restoreCompletedTransactions()</code> method of the payment queue we&#x2019;re triggering the process of restoring previous purchases.</p>



<p><em>Note: Restoring previous purchases regards only non-consumable products. Consumable products are not restored; users might have or might have not consumed them and it&#x2019;s up to you as a developer to synchronize that information among devices if necessary using cloud solutions (such as iCloud, your server, Firebase, etc).</em></p>



<p>Now, go to the <code>paymentQueue(_:updatedTransactions:)</code> delegate method in the <code>SKPaymentTransactionObserver</code> extension. If you remember, there&#x2019;s the <code>restored</code> case there which we had left unmanaged. Since in this method we go through all available transactions, we&#x2019;ll increase the <code>totalRestoredPurchases</code> value by one each time we have a restored one. At the end we&#x2019;ll know how many purchases were restored and how many weren&#x2019;t. Here&#x2019;s how the <code>restored</code> case should look:</p>



<pre class="wp-block-code"><code>case .restored:
    totalRestoredPurchases += 1
    SKPaymentQueue.default().finishTransaction(transaction)</code></pre>



<p>Notice that calling the <code>finishTransaction(_:)</code> method is necessary so the transaction is marked as finished in the payment queue.</p>



<p>We&#x2019;ll implement two more delegate methods now in the <code>SKPaymentTransactionObserver</code> extension&#x2019;s body. The one you&#x2019;ll see right next is called whenever restoring previous purchases has finished successfully, meaning without any errors, <em>even if there are not any products to restore</em>.</p>



<pre class="wp-block-code"><code>func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
    if totalRestoredPurchases != 0 {
        onBuyProductHandler?(.success(true))
    } else {
        print(&quot;IAP: No purchases to restore!&quot;)
        onBuyProductHandler?(.success(false))
    }
}</code></pre>



<p>Two things to mention here: Firstly, see that in both cases we call the <code>onBuyProductHandler</code> passing <code>success</code> as the result&#x2019;s value. The associated value of the success cases varies depending on whether we had restored products or not. Secondly, the way <code>totalRestoredPurchases</code> property is used here is something you can change and make it fit to the needs of your own app. In this demo app it&#x2019;s sufficient to know that <code>totalRestoredPurchases != 0</code>, since we have one non-consumable product only and this condition ensures that it&#x2019;s restored successfully. If you have more than one restorable products, you might need to change it and calculate the products that were not restored.</p>



<p>The second delegate method is invoked by the payment queue on a failed restore process. Note that a reason for the failure could be users themselves by just cancelling the entire process. You&#x2019;ll find it familiar as we&#x2019;re doing the exact same thing as we did in the <code>failed</code> case in the <code>paymentQueue(_:updatedTransactions:)</code> method. Here it is:</p>



<pre class="wp-block-code"><code>func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
    if let error = error as? SKError {
        if error.code != .paymentCancelled {
            print(&quot;IAP Restore Error:&quot;, error.localizedDescription)
            onBuyProductHandler?(.failure(error))
        } else {
            onBuyProductHandler?(.failure(IAPManagerError.paymentWasCancelled))
        }
    }
}</code></pre>



<p>And that concludes the implementation of the <code>IAPManager</code> class! It&#x2019;s about time to run our last test.</p>



<h2 class="wp-block-heading">Enabling App To Restore Purchases</h2>



<p>Open the <em>ViewModel.swift</em> file and go to the <code>restorePurchases()</code> method. This one is called by the <code>restorePurchases(_:)</code> IBAction method in the <code>ViewController</code> class. Similarly to what we did before, we&#x2019;ll indicate a long process to the view controller, and then we&#x2019;ll initiate the restore process:</p>



<pre class="wp-block-code"><code>func restorePurchases() {
    delegate?.willStartLongProcess()
    IAPManager.shared.restorePurchases { (result) in

    }
}</code></pre>



<p>When the closure gets called, we&#x2019;ll examine the success value of the result. If it&#x2019;s true, then restoring the product was successful and we can unlock all maps on our fake game. If not we&#x2019;ll display an appropriate message, which is also the case when restoring fails.</p>



<pre class="wp-block-code"><code>DispatchQueue.main.async {
    self.delegate?.didFinishLongProcess()

    switch result {
    case .success(let success):
        if success {
            self.restoreUnlockedMaps()
            self.delegate?.didFinishRestoringPurchasedProducts()
        } else {
            self.delegate?.didFinishRestoringPurchasesWithZeroProducts()
        }

    case .failure(let error): self.delegate?.showIAPRelatedError(error)
    }
}</code></pre>



<p>See that we treat separately the case where there are no products to restore (the <code>didFinishRestoringPurchasesWithZeroProducts()</code> delegate method is called). You&#x2019;re not required, but recommended to do so in your apps as well so you can notify your users properly.</p>



<p>In order to test the restore functionality, first buy the &#x201C;unlock all maps&#x201D; in-app purchase and then delete the app from your device. Install it again through Xcode and then tap on the <em>Restore Purchases</em> button using <em>the same test user</em> you used before.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="576" height="1024" src="https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-576x1024.png" alt="A Complete Guide to In-App Purchases for iOS Development" class="wp-image-17359" srcset="https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-576x1024.png 576w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-200x356.png 200w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-169x300.png 169w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-768x1365.png 768w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-1240x2204.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-860x1529.png 860w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-680x1209.png 680w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-400x711.png 400w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps-50x89.png 50w, https://www.appcoda.com/content/images/wordpress/2019/10/t68_30_restore_iaps.png 1242w" sizes="(max-width: 576px) 100vw, 576px"></figure>



<h2 class="wp-block-heading">Summary</h2>



<p>Offering in-app purchases through an app is not a complicated process, but it involves a lot of steps. Starting with the preparation on the App Store and finishing by adding the last touch in your code consists of a series of actions that must be done really carefully. The detailed parts presented in this post show the way to integrate in-app purchases in your app, and by leaving here you can keep the <code>IAPManager</code> class as a reusable component which you can extend according to your needs. Always make sure to be in align with the Apple&#x2019;s recommendations and best practices regarding in-app purchases. With that said it&#x2019;s about time to let you rest because you&#x2019;ve just gone through a long tutorial, which I hope you found useful. Thanks for reading and&#x2026; happy earnings!</p>



<p>For the full source code, you can refer to <a href="https://github.com/appcoda/In-app-Purchase-Game-Demo/?ref=appcoda.com">this project</a> on GitHub.</p>



<p><em>Credits: Images by <a href="https://icons8.com/?ref=appcoda.com">icons8</a></em></p>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[Vision Framework: Working with Text and Image Recognition in iOS]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>2 years ago, at WWDC 2017, Apple released the <em>Vision</em> framework, an amazing, intuitive framework that would make it easy for developers to add computer vision to their apps. Everything from text detection to facial detection to barcode scanners to integration with Core ML was covered in this framework. </p>



<p>This</p>]]></description><link>https://www.appcoda.com/animal-recognition-vision-framework/</link><guid isPermaLink="false">66612a0f166d3c03cf0114ae</guid><category><![CDATA[AI]]></category><category><![CDATA[iOS Programming]]></category><category><![CDATA[Swift]]></category><dc:creator><![CDATA[Sai Kambampati]]></dc:creator><pubDate>Thu, 12 Sep 2019 01:30:34 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2019/09/mzgrja-kyla.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2019/09/mzgrja-kyla.jpg" alt="Vision Framework: Working with Text and Image Recognition in iOS"><p>2 years ago, at WWDC 2017, Apple released the <em>Vision</em> framework, an amazing, intuitive framework that would make it easy for developers to add computer vision to their apps. Everything from text detection to facial detection to barcode scanners to integration with Core ML was covered in this framework. </p>



<p>This year, at WWDC 2019, Apple released several more new features to this framework that really push the field of computer vision. That&#x2019;s what we&#x2019;ll be looking at in this tutorial.</p>



<h2 class="wp-block-heading">What We&#x2019;ll be Building in this Tutorial</h2>



<p>For many years now, Snapchat has reigned as the popular social media app among teens. With its simple UI and great AR features, high schoolers around the world love to place cat/dog filters themselves. <strong>Let&#x2019;s flip the script!</strong></p>



<p>In this tutorial, we&#x2019;ll be building <em>Snapcat</em>, the Snapchat for Cats. Using <code>Vision</code>&#x2019;s new animal detector, we&#x2019;ll be able to detect cats, place the human filter on them, and take pictures of them. After taking pictures of our cats, we&#x2019;ll want to scan their business cards. Using a brand new framework, <code>VisionKit</code>, we&#x2019;ll be able to scan their business cards just like the default Notes app on iOS.</p>



<p>That&#x2019;s not all! If you remember 2 years ago my tutorial on using <a href="https://www.appcoda.com/vision-framework-introduction/">Vision for text detection</a>, I ended by saying that even though you could detect text, you would still need to integrate the code with a <code>Core ML</code> model to recognize each character. Well finally, Apple has released a new class under <code>Vision</code> to recognize the text it detects. We&#x2019;ll use this new class to grab the information from the scanned cards and assign it to our cat. Let&#x2019;s get started!</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="489" src="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-1024x489.jpg" alt="Vision Framework: Working with Text and Image Recognition in iOS" class="wp-image-17193" srcset="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-1024x489.jpg 1024w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-200x96.jpg 200w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-600x287.jpg 600w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-768x367.jpg 768w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-1680x802.jpg 1680w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-1240x592.jpg 1240w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-860x411.jpg 860w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-680x325.jpg 680w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-400x191.jpg 400w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework-50x24.jpg 50w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-demo-vision-framework.jpg 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>The project in this tutorial was built using Swift 5.1 in Xcode 11 Beta 7 running on macOS Catalina. If you face any errors when go through the tutorial, try to update your Xcode to the latest version or leave a comment below.</p>



<h2 class="wp-block-heading">Getting the Starter Project</h2>



<p>To begin, download the starter project <a href="https://github.com/appcoda/ImageRecognitionDemo/raw/master/starter.zip?ref=appcoda.com">here</a>. Build and run on your device. What we have is the iconic Snapchat camera view. To create this, I added a <code>ARSCNView</code>, or an <code>SceneView</code> that is capable of displaying AR content, and overplayed it with a button. </p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="988" src="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-1024x988.jpg" alt="Vision Framework: Working with Text and Image Recognition in iOS" class="wp-image-17195" srcset="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-1024x988.jpg 1024w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-200x193.jpg 200w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-311x300.jpg 311w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-768x741.jpg 768w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-1680x1621.jpg 1680w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-1240x1197.jpg 1240w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-860x830.jpg 860w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-680x656.jpg 680w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-400x386.jpg 400w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2-50x48.jpg 50w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-2.jpg 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>When the shutter button is pressed, the app takes a snapshot of the current frame of this scene view and passes it along the navigation stack to the Cat Profile View where it&#x2019;s loaded the profile image. In this view, we have empty fields for the data: <em>Name</em>, <em>Number</em>, and <em>Email</em>. This is because we haven&#x2019;t scanned the business card yet! Clicking on the button has no action yet because this is where we&#x2019;ll implement the document scanning program via <code>VisionKit</code>. </p>



<h2 class="wp-block-heading">Image Recognition &#x2013; Detecting a Cat Using VNRecognizeAnimalsRequest</h2>



<p>Our first step is to detect cats in our camera view. Head over to <code>CameraViewController</code> and at the top of the file, type <code>import Vision</code>. This imports the Vision framework into this file, giving us access to all the classes and functions. </p>



<p>Now we want our app to automatically place the human filter (&#x201C;the human emoji&#x201D;)  on our cat with no input from us whatsoever. This means that we need to scan the frames in our camera view every few milliseconds. To do this, modify your code to look like below:</p>



<pre class="wp-block-code"><code>@IBOutlet var previewView: ARSCNView!
var timer: Timer?

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let configuration = ARWorldTrackingConfiguration()
    previewView.session.run(configuration)
    timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(self.detectCat), userInfo: nil, repeats: true)

}</code></pre>



<p>We create an instance of <code>timer</code> and define it in our <code>viewWillAppear</code> function. We schedule the timer to perform the function <code>detectCat()</code> in the interval of every half a second.</p>



<p>However, you&#x2019;ll experience an error displayed because we have not created the function called <code>detectCat</code>. This is a simple fix. Here is the <code>viewWillAppear</code> function. Insert the code in the <code>CameraViewController</code> class:</p>



<pre class="wp-block-code"><code>@objc func detectCat() {
    print(&quot;Detected Cat!&quot;)
}</code></pre>



<p>Let&#x2019;s build and run the project so far. The moment our <code>CameraViewController</code> is initialized, we should see the text &#x201C;Detected Cat!&#x201D; printed to the console every half second.</p>



<p>Now here comes to the fun part where we&#x2019;ll use the new <code>VNRecognizeAnimalsRequest</code>, a built-in class that lets you detect cats and dogs.</p>



<p>Modify the <code>detectCat()</code> function to look like this:</p>



<pre class="wp-block-code"><code>@objc func detectCat() {
    guard let currentFrameBuffer = self.previewView.session.currentFrame?.capturedImage else { return }
    let image = CIImage(cvPixelBuffer: currentFrameBuffer)
    let detectAnimalRequest = VNRecognizeAnimalsRequest { (request, error) in
        DispatchQueue.main.async {
            if let results = request.results?.first as? VNRecognizedObjectObservation {
                let cats = result.labels.filter({$0.identifier == &quot;Cat&quot;})
                for cat in cats {
                    print(&quot;Found a cat!!&quot;)
                }
            }
        }
    }

    DispatchQueue.global().async {
        try? VNImageRequestHandler(ciImage: image).perform([detectAnimalRequest])
    }
}</code></pre>



<p>There&#x2019;s quite a bit going on here but I&#x2019;ll go through it line by line. First, we implement a <code>guard</code> function that checks to make sure that the current frame in our Preview View has an image. If this image can be captured, we create a special <code>CIImage</code> using the pixel buffer of that frame&#x2019;s image.</p>



<p>Here&#x2019;s some terminology! The <code>CIImage</code> class we&#x2019;re using is a representation for an image as a <code>CoreImage</code>. This type of images are great when you want to analyze the pixels in them.  A <em>pixel buffer</em> stores an image data in the main memory.</p>



<p>Before explaining the next few lines of code, it&#x2019;ll help to understand how Vision works in case you&#x2019;re unfamiliar. Basically, there are 3 steps to implement Vision in your app, which are:</p>



<ol><li><strong>Requests</strong> &#x2013; Requests are when you request the framework to detect something for you.</li><li><strong>Handlers</strong> &#x2013; Handlers are when you want the framework to perform something after the request is made or &#x201C;handle&#x201D; the request.</li><li><strong>Observations</strong> &#x2013; Observations are what you want to do with the data provided with you.</li></ol>



<p>So first, we create a <code>VNRecognizeAnimalRequest</code> to detect animals. This is a new <code>VNImageRequest</code> that was introduced in iOS 13 specifically for animal detection. </p>



<p>Next, within the handler of this request, we get the result and filter the labels in our first result. Why are we doing this? This is because currently, the <code>VNRecognizeAnimalRequest</code> can detect both cats and dogs. For our use, we only want cats which is why we define an array called <code>cats</code> where the identifier is equal to &#x201C;Cats&#x201D;. Finally, for each <code>cat</code> observation, we print that we found a cat to the console. This is just to see if Vision is detecting cats.</p>



<p>Remember, we&#x2019;ve only defined the request. Now we need to ask Vision to perform the request. After defining the request, we ask <code>VNImageRequestHandler</code> to perform the request on our <code>CIImage</code> we defined earlier. A <code>VNImageRequestHandler</code>  is basically a specific type of VNRequest that is used to process images using one or more image analysis requests.</p>



<p>Build and run the project on a device. I don&#x2019;t have a cat so I&#x2019;ll be using some images from online. If Vision correctly detects the cat, then we should be able to see it printed to the console.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="613" src="https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-1024x613.jpg" alt="Vision Framework: Working with Text and Image Recognition in iOS" class="wp-image-17196" srcset="https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-1024x613.jpg 1024w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-200x120.jpg 200w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-501x300.jpg 501w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-768x460.jpg 768w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-1680x1005.jpg 1680w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-1240x742.jpg 1240w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-860x515.jpg 860w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-680x407.jpg 680w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-400x239.jpg 400w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat-50x30.jpg 50w, https://www.appcoda.com/content/images/wordpress/2019/09/animal-recognition-cat.jpg 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>It works!! But how should we let users know that the app detects a cat? It&#x2019;s time to code again. </p>



<p>At the top of the class where we initialized the <code>timer</code> object, type the line: <code>var rectangleView = UIView()</code>. This initializes a <code>UIView</code> which we can modify to be a box. We&#x2019;ll place this box around the coordinates where our Vision function can detect the cat.</p>



<p>Inside the <code>detectCat()</code> method, insert <code>self.rectangleView.removeFromSuperview()</code> at the beginning. Then modify the <code>for</code> loop to look like this:</p>



<pre class="wp-block-code"><code>for cat in cats {
    self.rectangleView = UIView(frame: CGRect(x: result.boundingBox.minX * self.previewView.frame.width, y: result.boundingBox.minY * self.previewView.frame.height, width: result.boundingBox.width * self.previewView.frame.width, height: result.boundingBox.height * self.previewView.frame.height))

    self.rectangleView.backgroundColor = .clear
    self.rectangleView.layer.borderColor = UIColor.red.cgColor
    self.rectangleView.layer.borderWidth = 3
                        self.previewView.insertSubview(self.rectangleView, at: 0)
}</code></pre>



<p>Here&#x2019;s what we&#x2019;re doing. We are defining our <code>rectangleView</code> to have the bounds of the <code>result</code>&#x2019;s bounding box. However, this is something worth mentioning.</p>



<p>In Vision, the size of the result&#x2019;s bounding box is smaller than the size of your <code>previewView</code>. This is because when Vision analyzes the image, it scales down the image to speed up computer vision processes. That&#x2019;s why when we create the bounds for our <code>rectangleView</code>, we have the multiply it by the constant to scale it up.</p>



<p>After defining the frame, all we do is set the view to have a transparent background and a border of width 3 and color red. We add this to our <code>previewView</code>. Now, you may be wondering why we included the line of code <code>self.rectangleView.removeFromSuperview()</code> at the beginning of the function. Remember, our Vision code is running every half a second. If we don&#x2019;t remove the <code>rectangleView</code>, we&#x2019;ll have <strong>a lot</strong> of boxes on our view.</p>



<p>Ok! Build and run the app! Are you seeing the boxes?</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="400" height="790" src="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-9.png" alt="Vision Framework: Working with Text and Image Recognition in iOS" class="wp-image-17197" srcset="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-9.png 400w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-9-200x395.png 200w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-9-152x300.png 152w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-9-50x99.png 50w" sizes="(max-width: 400px) 100vw, 400px"></figure>



<p>Yes! It&#x2019;s working. Now we have one last thing to do: place a human emoji near the cat. This is really simple. Here&#x2019;s what we do. </p>



<p>Ath the top of the class, underneath where we define our <code>rectangleView</code>, type the line: <code>var humanLabel = UILabel()</code>. </p>



<p>Inside the <code>for</code> loop of our <code>detectCat()</code> function, we need to add this label to our view. Here&#x2019;s how to do that.</p>



<pre class="wp-block-code"><code>for cat in cats {
    self.rectangleView = UIView(frame: CGRect(x: result.boundingBox.minX * self.previewView.frame.width, y: result.boundingBox.minY * self.previewView.frame.height, width: result.boundingBox.width * self.previewView.frame.width, height: result.boundingBox.height * self.previewView.frame.height))

    self.humanLabel.text = &quot;&#x1F466;&quot;
    self.humanLabel.font = UIFont.systemFont(ofSize: 70)
    self.humanLabel.frame = CGRect(x: 0, y: 0, width: self.rectangleView.frame.width, height: self.rectangleView.frame.height)

    self.rectangleView.addSubview(self.humanLabel)
    self.rectangleView.backgroundColor = .clear
    self.previewView.insertSubview(self.rectangleView, at: 0)
} </code></pre>



<p>This is really easy to follow. We still have the same frame for our <code>rectangleView</code>. Now, we set the text of the label to be an emoji followed by the font size. Since we want the labels to cover the entire box, we set its width and height to be the same as the <code>rectangleView</code>. Finally, we removed the code that would create a border and instead add the label to our box and add the box to the <code>previewView</code>. </p>



<p>Build and run the app. Is the code working? Can you see the human emoji on the cat?</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="400" height="790" src="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-11.png" alt="Vision Framework: Working with Text and Image Recognition in iOS" class="wp-image-17198" srcset="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-11.png 400w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-11-200x395.png 200w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-11-152x300.png 152w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-11-50x99.png 50w" sizes="(max-width: 400px) 100vw, 400px"></figure>



<p>It works! We&#x2019;ve got a human emoji placed on the cat. Now, of course, it&#x2019;s not perfect because Vision only detects a cat object, not the facial features of the cat. Hopefully Apple will add that soon and we can further refine the filter.</p>



<h2 class="wp-block-heading">Scanning the Business Card Using VNDocumentCameraViewController</h2>



<p>Whew! We made it through the first part. From here on, it gets a little easier. When you snap the picture of your cat, you automatically get pushed to the Cat Profile view where you can see the image you&#x2019;ve taken, the details of the cat, and a button that says &#x201C;Scan For Details&#x201C;. We&#x2019;ll be pulling up the new document scanner code when this button is tapped on.</p>



<p>Navigate to <code>CatProfileViewController.swift</code>. At the top of the file, underneath <code>import UIKit</code>, type <code>import VisionKit</code>. The difference between <code>Vision</code> and <code>VisionKit</code> is that while <code>Vision</code> lets your perform computer vision analyses on an image, <code>VisionKit</code> is a small framework that lets your app use the system&#x2019;s document scanner.</p>



<p>Now within the <code>scanDocument()</code> function, all you need to add are three lines of code.</p>



<pre class="wp-block-code"><code>@IBAction func scanDocument(_ sender: Any) {
    let documentCameraViewController = VNDocumentCameraViewController()
    documentCameraViewController.delegate = self
    self.present(documentCameraViewController, animated: true, completion: nil)
}</code></pre>



<p>The <code>VNDocumentCameraViewController()</code> is a special type of view controller created by Apple which is used to scan the documents. We set the delegate of that controller and present the view controller. </p>



<p>Next, you need to implement the <code>VNDocumentCameraViewControllerDelegate</code> in the class. Change the line where we define out <code>CatProfileViewController</code> class to look like this.</p>



<pre class="wp-block-code"><code>class CatProfileViewController: UIViewController, VNDocumentCameraViewControllerDelegate {
    ....
}</code></pre>



<p>Build and run the app. After taking a picture, when you press &#x201C;Scan for Details&#x201D;, the device&#x2019;s document scanner should pop up.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="988" src="https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-1024x988.jpg" alt="Vision Framework: Working with Text and Image Recognition in iOS" class="wp-image-17202" srcset="https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-1024x988.jpg 1024w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-200x193.jpg 200w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-311x300.jpg 311w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-768x741.jpg 768w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-1680x1621.jpg 1680w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-1240x1197.jpg 1240w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-860x830.jpg 860w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-680x656.jpg 680w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-400x386.jpg 400w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-50x48.jpg 50w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition.jpg 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Looks like it&#x2019;s scanning! However, when we press &#x201C;Save&#x201D;, nothing happens. This is because we haven&#x2019;t implemented any delegate methods yet. Underneath, the <code>scanDocument()</code> function, type the following. </p>



<pre class="wp-block-code"><code>func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
    let image = scan.imageOfPage(at: 0)
    self.catImageView.image = image
    controller.dismiss(animated: true)
}</code></pre>



<p>The <code>documentCameraViewController(didFinishWith:)</code> is a method that runs when the Save button is clicked. We take the first scan, make it an image, and set the <code>catImageView</code> to display this image. We&#x2019;re doing this to make sure that the scanner is working well. </p>



<p>Build and run the app. When you have to scan for details, scan over any business card and when you click &#x201C;Save&#x201D;, it should dismiss the document scanner and set the image to the <code>catImageView</code>. </p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="988" src="https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-1024x988.jpg" alt="Vision Framework: Working with Text and Image Recognition in iOS" class="wp-image-17203" srcset="https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-1024x988.jpg 1024w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-200x193.jpg 200w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-311x300.jpg 311w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-768x741.jpg 768w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-1680x1621.jpg 1680w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-1240x1197.jpg 1240w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-860x830.jpg 860w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-680x656.jpg 680w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-400x386.jpg 400w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2-50x48.jpg 50w, https://www.appcoda.com/content/images/wordpress/2019/09/business-card-recognition-2.jpg 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Now that the app is able to detect the business card, let&#x2019;s further implement it to extract the textual data from the card.</p>



<h2 class="wp-block-heading">Text Recognition Using VNRecognizeTextRequest</h2>



<p>With the new API, <code>VNRecognizeTextRequest</code>, introduced in iOS 13, it&#x2019;s pretty easy to finds and recognizes text in an image.</p>



<p>Again, first <code>import VisionKit</code> in the file because the new API is bundled in the framework. As explained earlier, this will bring over the Vision API&#x2019;s. Next, before the <code>viewDidLoad()</code> function, type the following:</p>



<pre class="wp-block-code"><code>var textRecognitionRequest = VNRecognizeTextRequest()
var recognizedText = &quot;&quot; </code></pre>



<p>The <code>VNRecognizeTextRequest</code> is just like the <code>VNRecognizeAnimalsRequest</code> class that we&#x2019;ve used earlier. This request tells Vision to run text recognition on whatever image we pass to it. Later, when Vision detects text in a image, we&#x2019;ll assign it to the variable <code>recognizedText</code>. </p>



<p>Head over to the <code>viewDidLoad()</code> function and update the code like below:</p>



<pre class="wp-block-code"><code> override func viewDidLoad() {&#x2028;super.viewDidLoad()
    self.navigationController?.setNavigationBarHidden(false, animated: true)
    self.title = &quot;New Cat&quot;
    catImageView.image = catImage

    textRecognitionRequest = VNRecognizeTextRequest(completionHandler: { (request, error) in
        if let results = request.results, !results.isEmpty {
            if let requestResults = request.results as? [VNRecognizedTextObservation] {
                self.recognizedText = &quot;&quot;
                for observation in requestResults {
                    guard let candidiate = observation.topCandidates(1).first else { return }
                      self.recognizedText += candidiate.string
                    self.recognizedText += &quot;\n&quot;
                }
                self.catDetailsTextView.text = self.recognizedText
            }
        }
    })
}</code></pre>



<p>In the code, we initiate a <code>VNRecognizeTextRequest</code>. Vision returns the result of this request in a&#xA0;<a href="https://developer.apple.com/documentation/vision/vnrecognizedtextobservation?ref=appcoda.com"><code>VNRecognizedTextObservation</code></a>&#xA0;object. This type of observation contains information about both the location and content of text and glyphs that Vision recognized in the input image. </p>



<p>For every item in the <code>requestResults</code> array, we choose the first <code>topCandidates</code>. What is this? Well for every observation Vision makes, it outputs a list of potential candidates for the detected text. In some cases, it may be useful to consider all the possible text. For our case, we only care about the most accurate prediction.</p>



<p>Finally, we take the <code>candidate.string</code> and add it to our <code>recognizedText</code>. After going through every observation in the <code>requestResults</code> array, we set the text of the <code>catDetailsTextView</code> to our <code>recognizedText</code>.</p>



<p>Your code should look a little like the image below:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="613" src="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-1024x613.png" alt="Vision Framework: Working with Text and Image Recognition in iOS" class="wp-image-17204" srcset="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-1024x613.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-200x120.png 200w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-501x300.png 501w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-768x460.png 768w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-1680x1005.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-1240x742.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-860x515.png 860w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-680x407.png 680w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-400x239.png 400w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-16.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>You can build and run the app now but nothing will happen. Why? This is because we still haven&#x2019;t defined a handler to perform the request. This can be accomplished in a couple lines of code. Head back to the <code>documentCameraViewController(didFinishWith:)</code> function and modify it like this:</p>



<pre class="wp-block-code"><code>func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
    let image = scan.imageOfPage(at: 0)
    let handler = VNImageRequestHandler(cgImage: image.cgImage!, options: [:])
    do {
        try handler.perform([textRecognitionRequest])
    } catch {
        print(error)
    }
    controller.dismiss(animated: true)
}</code></pre>



<p>The code above should look familiar as we used it in the first section of the tutorial. We define a <code>handler</code> of type <code>VNImageRequestHandler</code> and input the <code>cgImage</code> of our scan.</p>



<p>A <code>VNImageRequestHandler</code> is an object that processes one or more image analysis requests pertaining to a single image. By specifying the image, we can begin executing the Vision request. In the <code>do</code> block, we ask the handler to perform the Vision request we defined earlier. x</p>



<p>Build and run the app. Is it working?</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="400" height="790" src="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-18.png" alt="Vision Framework: Working with Text and Image Recognition in iOS" class="wp-image-17205" srcset="https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-18.png 400w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-18-200x395.png 200w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-18-152x300.png 152w, https://www.appcoda.com/content/images/wordpress/2019/09/image-recognition-18-50x99.png 50w" sizes="(max-width: 400px) 100vw, 400px"></figure></div>



<p>It seems to be working quite well! We&#x2019;re able to gather all the text from the scanned card and place it onto the text view. </p>



<h2 class="wp-block-heading">Fine Tuning the Text Recognition</h2>



<p>Now in my image above, the text recognition worked great. However, I&#x2019;ll try to help you fine tune our <code>VNRecognizeTextRequest</code> in case it didn&#x2019;t work so well for you. </p>



<p>At the end of our <code>viewDidLoad()</code> function, type the following:</p>



<pre class="wp-block-code"><code>textRecognitionRequest.recognitionLevel = .accurate
textRecognitionRequest.usesLanguageCorrection = false
textRecognitionRequest.customWords = [&quot;@gmail.com&quot;, &quot;@outlook.com&quot;, &quot;@yahoo.com&quot;, &quot;@icloud.com&quot;] </code></pre>



<p>These are some of the values that the <code>VNRecognizeTextRequest</code> has. You can modify them to fine tune your application. Let&#x2019;s go through these.</p>



<ol><li><code>.recognitionLevel</code>: You have two options between these: <code>.fast</code> and <code>.accurate</code>. When you want the request to recognize text, you can choose between recognizing faster or more accurately. Apple advices to use <code>.accurate</code> because even though it take slightly more time, it works well for recognizing texts in custom font shapes and size. The advantage with <code>.fast</code> is that it takes up less memory on the device.</li><li><code>.usesLanguageCorrection</code>: Here&#x2019;s how Vision Text Recognition Request works. After grabbing the text from each observation, it doesn&#x2019;t just output that text to you. It goes through another layer of Natural Language to change any misspelled words. Think if it like a spell and grammar check. By changing this Boolean value, you can enable this on or off. When should you set this to true? If your application is being used to recognize text from a book or a document, then you should enable this setting. However, in our scenario, we&#x2019;re using it to detect names, numbers, and email addresses. If we enable this setting, it&#x2019;s possible that the request may think the number <em>1</em> is the lowercase letter <em>l</em>. Or another example is the last name <em>He</em> which Vision may correct to <em>Hey</em> or <em>Hi</em>. </li><li><code>.customWords</code>: This value is an array that can be used for specific words. In our scenario, we&#x2019;re detecting emails which generally end in <em>@email.com</em>. While this isn&#x2019;t a word on its own, we wouldn&#x2019;t want Vision predicting these characters to be something else. By offering custom words, the text recognition request analyzes the image a second time to see if any of those words appear so it can recognize them properly.</li></ol>



<p>Build and run the app. Is there any improvement? Did the recognition system get better or worse? By fine tuning these parameters, you can utilize Vision&#x2019;s text recognition system to be the best in your app.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>In this tutorial, as you can see, it is so easy to take advantage of all the new API&#x2019;s in Vision to perform object recognition. You learned how we can use the brand new animal detector to recognize cats and dogs in an image. You should also understand how the new framework, <code>VisionKit</code>, makes scanning documents a breeze. Finally, the coveted text recognition APIs became available in Vision. With easy-to-use API&#x2019;s and lots of parameters for fine tuning the system, you can easily implement text recognition in your apps.</p>



<p>However, this isn&#x2019;t all that was announced at WWDC 2019. Vision also introduced API&#x2019;s to classify images into categories, analyze saliency, and detect human rectangles. I&#x2019;ve attached some great links if you want to  continue learning more about Vision.</p>



<ul><li><a href="https://developer.apple.com/documentation/vision?ref=appcoda.com">Vision Documentation</a></li><li><a href="https://developer.apple.com/videos/play/wwdc2019/222/?ref=appcoda.com">WWDC 2019 Session: Understanding Images in Vision Framework</a></li><li><a href="https://developer.apple.com/videos/play/wwdc2019/234?ref=appcoda.com">WWDC 2019 Session: Text Recognition in Vision Framework</a></li><li><a href="https://www.appcoda.com/vision-framework-introduction/">AppCoda Tutorial: Using Vision Framework for Text Detection in iOS 11</a></li></ul>



<p>I&#x2019;d love to know what you&#x2019;re building with Vision! Leave a comment below if you have a question or want to share what you&#x2019;re working on. You can <a href="https://github.com/appcoda/ImageRecognitionDemo?ref=appcoda.com">download the full tutorial here</a>. Thanks for reading! Catch you in the next article!</p>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[Building a Flutter App with Complex UI]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>Hello there! Welcome to the second tutorial of our Flutter series. In the last <a href="https://www.appcoda.com/flutter-basics/">tutorial</a>, you learned the basics of building a Flutter app. So if you have not gone through it, please take a pit stop here, visit it first before proceeding with this tutorial.</p>



<h2 class="wp-block-heading">What will you learn?</h2>]]></description><link>https://www.appcoda.com/flutter-app-complex-ui/</link><guid isPermaLink="false">66612a0f166d3c03cf0114a9</guid><category><![CDATA[iOS Programming]]></category><dc:creator><![CDATA[Lawrence Tan]]></dc:creator><pubDate>Fri, 16 Aug 2019 14:03:49 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2019/08/tim-mossholder-VOXs79vySFo-unsplash.jpg" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2019/08/tim-mossholder-VOXs79vySFo-unsplash.jpg" alt="Building a Flutter App with Complex UI"><p>Hello there! Welcome to the second tutorial of our Flutter series. In the last <a href="https://www.appcoda.com/flutter-basics/">tutorial</a>, you learned the basics of building a Flutter app. So if you have not gone through it, please take a pit stop here, visit it first before proceeding with this tutorial.</p>



<h2 class="wp-block-heading">What will you learn?</h2>



<p>In today&#x2019;s tutorial, we will build an app with complex UI with the Flutter framework. We will explore quite a lot of components. By going through the tutorial, you will learn to implement:</p>



<ul><li>Textfields with Validation</li><li>Centralized App Theme</li><li>Carousel Slider</li><li>List View</li><li>Complex List View</li><li>Basic Form</li><li>Scoped Model</li></ul>



<p>If any of the above raises your eyebrow, then you are here at the right place! Tighten your seatbelt as this tutorial will take you on a ride to learn all these concepts, by building an app called <em>Moments</em>.</p>



<h2 class="wp-block-heading">Moments App</h2>



<p>Moments App is a simple app that has the following screens:</p>



<ul><li>Login Screen  </li><li>Gallery Screen</li><li>Menu Screen</li><li>Form Screen</li><li>List Screen</li><li>Rich List Screen</li></ul>



<p>You will build the screens sequentially, learn the different ways of wiring up views. And, this is how the final app will look like:</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="300" height="650" src="https://www.appcoda.com/content/images/wordpress/2019/08/demoapp.gif" alt="Building a Flutter App with Complex UI" class="wp-image-17061"></figure></div>



<p>Let&#x2019;s get started!</p>



<h2 class="wp-block-heading">Getting Started</h2>



<p>Please proceed to download the <a href="https://github.com/lawreyios/FlutterMoments/tree/starter_project?ref=appcoda.com">starter project</a> and spend about 10-15 minutes to look through the code. The app has 4 main folders:</p>



<ul><li>Model</li><li>Pages</li><li>Scoped Models</li><li>Utils</li></ul>



<p>With 2 additional files <code>main.dart</code> and <code>app.dart</code>. Most of the functions are marked with <code>// TODO</code>, so you can implement its logic to build the components. </p>



<h3 class="wp-block-heading">Login Screen</h3>



<p>Let&#x2019;s first take a look at how the completed Login Screen is:</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="414" height="896" src="https://www.appcoda.com/content/images/wordpress/2019/08/app1.png" alt="Building a Flutter App with Complex UI" class="wp-image-17062" srcset="https://www.appcoda.com/content/images/wordpress/2019/08/app1.png 414w, https://www.appcoda.com/content/images/wordpress/2019/08/app1-200x433.png 200w, https://www.appcoda.com/content/images/wordpress/2019/08/app1-139x300.png 139w, https://www.appcoda.com/content/images/wordpress/2019/08/app1-400x866.png 400w, https://www.appcoda.com/content/images/wordpress/2019/08/app1-50x108.png 50w" sizes="(max-width: 414px) 100vw, 414px"></figure></div>



<p>It has the following UI components:</p>



<ul><li>Image</li><li>Title Text</li><li>TextField Title Text</li><li>TextField</li><li>Button</li></ul>



<p>Proceed to <code>login.dart</code>. Here you will first implement the login textfield, start by adding this ladder of codes:</p>



<pre class="wp-block-code"><code>Widget _buildLoginTextField() {
  // TODO #1: Implement Login Text Field
  return Theme(
    data: ThemeData(
      primaryColor: kRegistrationBlack,
      primaryColorDark: kRegistrationBlack,
    ),
    child: TextFormField(
      style: Theme.of(context).textTheme.subtitle,
      controller: _mobileNumberController,
      maxLength: 4,
      enableInteractiveSelection: false,
      keyboardType: TextInputType.number,
      textInputAction: TextInputAction.next,
      onFieldSubmitted: (value) {
        loginUser();
      },
      decoration: InputDecoration(
        fillColor: kRegistrationBlack,
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(5.0),
        ),
        contentPadding:
            EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
        labelText: LOGIN_LABEL_TEXT,
        suffixIcon: IconButton(
          icon: Icon(
            Icons.clear,
            color: kRegistrationBlack,
          ),
          onPressed: () {
            _mobileNumberController.clear();
            _mobileNumber = &apos;&apos;;
          },
        ),
      ),
      validator: (String value) {
        if (value.isEmpty || value.length != 4) {
          return &apos;Please enter a valid 4 digit code.&apos;;
        }
      },
      onSaved: (String value) {
        _mobileNumber = value;
      },
    ),
  );
}</code></pre>



<p>In this code, you returned a Theme Widget with a child of TextFormField. You should take a look at&#xA0;<code>theme.dart</code>&#xA0;to see how the theme data is set before proceeding further. Using a centralised theme, any view that requires a text style can easily reference by calling&#xA0;<code>Theme.of(context).textTheme.[styleType]</code>.</p>



<p>You should take a look at these codes to understand how this view is built as they will be repeatedly used in this tutorial. This is how the TextField is created:</p>



<ul><li>Theme<ul><li>ThemeData</li><li>TextFormField<ul><li>InputDecoration<ul><li>OutlineInputBorder</li><li>IconButton</li></ul></li></ul></li></ul></li></ul>



<p>The <code>TextFormField</code> has an <code>OutlineInputBorder</code> and a <em>Clear</em> <code>IconButton</code>, wrapped in <code>Theme</code>. It has a <code>mobileNumberController</code> which handles input text, and a <code>validator</code> for validation checks. <code>onFieldSubmitted</code> is triggered when the <code>textInputAction</code> is activated. To find out more about <code>TextFormField</code>, read the documentation <a href="https://api.flutter.dev/flutter/material/TextFormField-class.html?ref=appcoda.com">here</a>.</p>



<p>Moving on to the <em>Enter</em> <code>button</code>, a <em>custom button</em> has been created for you in <code>buttons.dart</code>. Here, you will just need to initialise a <code>MomentsButton</code> like this and since the button needs to be centered, wrap it with <code>Center</code>:</p>



<pre class="wp-block-code"><code>  Widget _buildEnterButton(BuildContext context) {
    // TODO #2: Implement Enter Button
    return Center(
        child:
            MomentsButton(text: ENTER, action: loginUser).getButton(context));
  }</code></pre>



<p>The final step to complete this page is to layer everything into the body properties in&#xA0;<code>build</code>&#xA0;function:</p>



<pre class="wp-block-code"><code>  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color(0xFFF9F9F9),
      // TODO #3: Implement Login View
      body: SafeArea(
        child: ListView(
          padding: EdgeInsets.symmetric(horizontal: 24.0),
          children: &lt;Widget&gt;[
            SizedBox(height: 80.0),
            Column(
              children: &lt;Widget&gt;[
                Image.asset(
                  &apos;assets/LOGO.png&apos;,
                  height: 150.0,
                ),
                SizedBox(height: 12.0),
                Text(&apos;Moments&apos;, style: Theme.of(context).textTheme.caption),
              ],
            ),
            SizedBox(height: 50.0),
            Text(&apos;Login:&apos;, style: Theme.of(context).textTheme.subtitle),
            SizedBox(height: 10.0),
            AccentColorOverride(
              color: kRegistrationBlack,
              child: Form(
                key: _formKey,
                child: _buildLoginTextField(),
              ),
            ),
            _buildEnterButton(context)
          ],
        ),
      ),
    );
  }</code></pre>



<ul><li>Scaffold<ul><li>SafeArea<ul><li>ListView<ul><li>Column<ul><li>Image</li><li>Text</li></ul></li><li>Text</li><li>Login TextField</li><li>Enter Button</li></ul></li></ul></li></ul></li></ul>



<p>You are starting to see that the best way to arrange views vertically is to use <a href="https://api.flutter.dev/flutter/widgets/Column-class.html?ref=appcoda.com">Column</a>. <a href="https://api.flutter.dev/flutter/widgets/SafeArea-class.html?ref=appcoda.com">SafeArea</a> here is used to handle any view changes caused by the keyboard. </p>



<p><a href="https://api.flutter.dev/flutter/widgets/ListView-class.html?ref=appcoda.com">ListView</a> automatically helps you handle any overflowing views and it includes a scrolling mechanism. <a href="https://api.flutter.dev/flutter/widgets/SizedBox-class.html?ref=appcoda.com">SizedBox</a> is used to specify fixed spaces between views.</p>



<p>With the Login Screen completed, many classes of views and components were introduced, and you will see them in action more as you build the next few pages. </p>



<p>Now let&#x2019;s run the app, try to key in a wrong code <code>1111</code> and then a correct code <code>1234</code>, and then move on to the <strong>Gallery Screen</strong>!</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>You will not dive deep into how <code>Scoped Models</code> work in this app. You can open <code>user.dart</code> to see the login logic, and explore this <a href="https://fluttercrashcourse.com/blog/scoped-model-goto?ref=appcoda.com">crash course</a>. In a nutshell, <code>Scoped Model</code> is used to manage variables that will live in the lifetime of the app.</p></blockquote>



<h2 class="wp-block-heading">Gallery Screen</h2>



<p>Next, we will build the Gallery screen. You will use&#xA0;<a href="https://pub.dev/packages/carousel_slider?ref=appcoda.com">Carousel Slider</a>&#xA0;to build an image slider, and again, add a button to move to the next screen. Proceed to&#xA0;<code>gallery.dart</code>&#xA0;to get started.</p>



<p>Firstly, if you look at our <code>assets</code> folder, you notice there are already pre-loaded images labelled <code>pic1.jpg</code> etc. These are also declared in an array of strings call <code>imgList</code>. </p>



<p>Using the pre-created <code>map</code> function, you map them each into a <code>Container</code> so the output result is actually a <code>List</code> of <code>Containers</code>:</p>



<pre class="wp-block-code"><code>List _getChildren(MainModel model) {
  // TODO #4: Implement List
  final List&lt;String&gt; images = imgList;
  return map&lt;Widget&gt;(
    images,
    (int index, String url) {
      return Container(
        decoration:
            BoxDecoration(border: Border.all(width: 10.0, color: Colors.white)),
        margin: EdgeInsets.all(5.0),
        child: Image.asset(
          url,
          fit: BoxFit.cover,
          width: 261.0,
          height: 353.0,
        ),
      );
    },
  ).toList();
}</code></pre>



<p>With the&#xA0;<code>List</code>&#xA0;of&#xA0;<code>Containers</code>&#xA0;ready, you can now load them into the&#xA0;<code>Carousel</code>&#xA0;like this in&#xA0;<code>_CarouselWithIndicatorState</code>&#xA0;class:</p>



<pre class="wp-block-code"><code>  @override
  Widget build(BuildContext context) {
    final List&lt;String&gt; images = imgList;
    // TODO #5: Implement Carousel
    return Column(children: [
      CarouselSlider(
        items: _getChildren(),
        autoPlay: true,
        height: 353,
        enlargeCenterPage: true,
        onPageChanged: (index) {
          setState(() {
            _current = index;
          });
        },
      ),
      Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: map&lt;Widget&gt;(
          images,
          (int index, String url) {
            return Container(
                width: 8.0,
                height: 24.0,
                margin: EdgeInsets.symmetric(vertical: 2.0, horizontal: 2.0),
                decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    color:
                        _current == index ? kRegistrationBlack : Colors.white));
          },
        ),
      ),
    ]);
  }</code></pre>



<p>Again, <code>Column</code> is used to layout 2 views vertically:</p>



<ul><li>View #1 &#x2013; Carousel</li><li>View #2 &#x2013; Row of Carousel Indicators</li></ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>If you can using <a href="https://code.visualstudio.com/?ref=appcoda.com">Visual Studio Code</a> and using a MAC machine, you can whole <code>CMD</code> and hover on <code>CarouselSlider</code> to view more information about this class. </p></blockquote>



<p>The <code>MomentsButton</code> can be created just like the previous one you have built:</p>



<pre class="wp-block-code"><code>    Widget _buildMomentsButton(BuildContext context) {
      // TODO #6: Implement Button
      return Center(
        child: MomentsButton(text: &apos;MOMENTS&apos;, action: _goToHomePage)
            .getButton(context),
      );
    }</code></pre>



<p>Having a custom class helps minimise repeated codes.</p>



<p>The last step for this page is to link everything up in <code>build</code>, add these codes after <code>_buildMomentsButton</code>:</p>



<pre class="wp-block-code"><code>    return Scaffold(
      appBar: PreferredSize(
        preferredSize: Size.fromHeight(30.0), // here the desired height
        child: AppBar(backgroundColor: kPlatinum, elevation: 0.0),
      ),
      backgroundColor: kPlatinum,
      // TODO #7: Implement Gallery
      body: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: &lt;Widget&gt;[
          Padding(
            padding: EdgeInsets.only(top: 8.0, bottom: 24.0),
            child: Text(&apos;Moments&apos;, style: Theme.of(context).textTheme.caption),
          ),
          Expanded(
            child: SizedBox(
              height: 200.0,
              child: ListView(children: &lt;Widget&gt;[
                Padding(
                  padding: EdgeInsets.symmetric(vertical: 15.0),
                  child: Column(
                    children: [
                      CarouselWithIndicator(),
                    ],
                  ),
                ),
              ]),
            ),
          ),
          Padding(
              padding: EdgeInsets.only(bottom: 24.0),
              child: _buildMomentsButton(context))
        ],
      ),
    );</code></pre>



<p><a href="https://api.flutter.dev/flutter/widgets/PreferredSize-class.html?ref=appcoda.com">PreferredSize</a>&#xA0;is used to give&#xA0;<code>AppBar</code>&#xA0;a fixed size. Using&#xA0;<code>MainAxisAlignment.start</code>&#xA0;positions its children views in a&#xA0;<strong>top-down</strong>&#xA0;approach.</p>



<p>Run the app and you should see a nice carousel slide show :-).</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="414" height="896" src="https://www.appcoda.com/content/images/wordpress/2019/08/app2.png" alt="Building a Flutter App with Complex UI" class="wp-image-17063" srcset="https://www.appcoda.com/content/images/wordpress/2019/08/app2.png 414w, https://www.appcoda.com/content/images/wordpress/2019/08/app2-200x433.png 200w, https://www.appcoda.com/content/images/wordpress/2019/08/app2-139x300.png 139w, https://www.appcoda.com/content/images/wordpress/2019/08/app2-400x866.png 400w, https://www.appcoda.com/content/images/wordpress/2019/08/app2-50x108.png 50w" sizes="(max-width: 414px) 100vw, 414px"></figure></div>



<h2 class="wp-block-heading">Menu Screen</h2>



<p>You are now down to just 3 more main screens to build, with a Menu Container Screen. In&#xA0;<code>gallery.dart</code>, you ended with a&#xA0;<code>MomentsButton</code>&#xA0;which navigates user to&#xA0;<code>MainPage</code>.</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="414" height="896" src="https://www.appcoda.com/content/images/wordpress/2019/08/app3.jpg" alt="Building a Flutter App with Complex UI" class="wp-image-17064" srcset="https://www.appcoda.com/content/images/wordpress/2019/08/app3.jpg 414w, https://www.appcoda.com/content/images/wordpress/2019/08/app3-200x433.jpg 200w, https://www.appcoda.com/content/images/wordpress/2019/08/app3-139x300.jpg 139w, https://www.appcoda.com/content/images/wordpress/2019/08/app3-400x866.jpg 400w, https://www.appcoda.com/content/images/wordpress/2019/08/app3-50x108.jpg 50w" sizes="(max-width: 414px) 100vw, 414px"></figure></div>



<p>Open up <code>main.dart</code> in <code>pages</code> folder, and in this page, there will be 3 menu buttons at the top, which when each one is being tapped, it will switch the child view to its respective view.</p>



<p>Let&#x2019;s start by implementing <code>buildMenuItems</code>:</p>



<pre class="wp-block-code"><code>  List&lt;Widget&gt; buildMenuItems(MainModel model) {
    // TODO #8: Implement Building of Menu Items
    final List&lt;String&gt; images = [
      &apos;assets/menu_form.png&apos;,
      &apos;assets/menu_list.png&apos;,
      &apos;assets/menu_richList.png&apos;
    ];

    final List&lt;String&gt; menuTitles = [&apos;Form&apos;, &apos;List&apos;, &apos;RichList&apos;];

    final List&lt;MenuItem&gt; menuItems = [
      MenuItem.form,
      MenuItem.list,
      MenuItem.richList
    ];

    final List&lt;Widget&gt; columnItems = List&lt;Widget&gt;();

    for (var i = 0; i &lt; menuTitles.length; i++) {
      bool isSelectedMenuItem = selectedMenuItem == menuItems[i];
      columnItems.add(
        Container(
          decoration: BoxDecoration(
              borderRadius: BorderRadius.all(Radius.circular(4.0)),
              border: Border.all(
                  color:
                      isSelectedMenuItem ? kRegistrationBlack : Colors.white)),
          child: InkWell(
            onTap: () {
              setState(() {
                selectedMenuItem = menuItems[i];
              });
            },
            child: Padding(
              padding: EdgeInsets.all(12.0),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                mainAxisAlignment: MainAxisAlignment.center,
                children: &lt;Widget&gt;[
                  Image(
                    image: AssetImage(images[i]),
                    height: 40,
                    width: 40,
                    color: kRegistrationBlack,
                  ),
                  Container(
                    margin: EdgeInsets.only(top: 4),
                    child: Text(menuTitles[i],
                        style: Theme.of(context).textTheme.display1),
                  )
                ],
              ),
            ),
          ),
        ),
      );
    }

    return columnItems;
  }</code></pre>



<p>Wow! That&#x2019;s really a lot of code. It does look intimidating, but actually, they are really simple. Logically, every MenuButton is made up of:</p>



<ol><li>Image</li><li>Title</li><li>MenuItem Type (Enum)</li></ol>



<p>At the end, you get the complete view likes this:</p>



<ul><li>Container<ul><li>InkWell (Allows Tap)<ul><li>Column<ul><li>Image</li><li>Text</li></ul></li></ul></li></ul></li></ul>



<p>This is one way you actually build a customised button. InkWell brings in the ability to implement <code>onTap</code> event. The function also uses <code>isSelectedMenuItem</code> to render a bordered or non-bordered view. At the end of this function, it returns the columns as a <code>List</code>. </p>



<p>Next, implement <code>getPage</code> which returns the selected page object:</p>



<pre class="wp-block-code"><code>  Widget getPage(MainModel model) {
    // TODO #9: Implement Menu Items Population
    switch (selectedMenuItem) {
      case MenuItem.form:
        return FormPage();
      case MenuItem.list:
        return ItemListPage(model);
      case MenuItem.richList:
        return RichListPage();
        break;
    }
  }</code></pre>



<p>And, finally, implement the&#xA0;<code>Column</code>&#xA0;view which has a&#xA0;<code>Row</code>&#xA0;that contains all the customised buttons:</p>



<pre class="wp-block-code"><code>  @override
  Widget build(BuildContext context) {
    final MainModel _model = ScopedModel.of(context);

    return Scaffold(
      backgroundColor: kMomentsWhite,
      appBar: AppBar(
        centerTitle: true,
        title: Text(&apos;Menu&apos;, style: Theme.of(context).textTheme.headline),
        backgroundColor: Colors.white,
        elevation: 0.0,
        actions: &lt;Widget&gt;[
          IconButton(
            icon: Icon(Icons.exit_to_app),
            onPressed: () {
              _model.logout();
              Navigator.of(context).pushReplacementNamed(&apos;/login&apos;);
            },
          ),
        ],
      ),
      // TODO #10: Implement Child View
      body: Column(
        children: &lt;Widget&gt;[
          Padding(
            padding: EdgeInsets.only(top: 12.0, bottom: 12.0),
            child: Container(
              color: Colors.white,
              child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: buildMenuItems(_model)),
            ),
          ),
          Padding(
            padding: EdgeInsets.only(bottom: 8),
            child: Text(&quot;Hello ${_model.user.name}!&quot;,
                style: Theme.of(context).textTheme.headline),
          ),
          Expanded(child: getPage(_model))
        ],
      ),
    );
  }</code></pre>



<p>In the&#xA0;<code>Row</code>&#xA0;here,&#xA0;<code>MainAxisAlignment.spaceEvenly</code>&#xA0;helps to spread the views evenly as the screen size changes. In the next layer, a simple Welcome message is shown. Followed by the child view which is rendered by&#xA0;<code>getPage</code>.</p>



<p>Run the app now and you should be able to tap on each of the button, see them being selected! Nothing much happens at the child view yet as they are not implemented. That is up next!</p>



<h2 class="wp-block-heading">Form Screen</h2>



<p>Next, we&#x2019;ll implement the form screen. Open&#xA0;<code>form.dart</code>. In most of the apps you are using now, it&#x2019;s common to implement a page with a form to submit information. Here&#x2019;s a quick way to <a href="https://github.com/lawreyios/FlutterMoments/blob/final_project/lib/pages/form.dart?ref=appcoda.com">implement a form</a> with radio buttons, checkbox and also a counter.</p>



<h3 class="wp-block-heading">Name Text Field</h3>



<p>The textfield is completely similar to the one you have implemented in the login screen, with the exception that here a&#xA0;<code>ListTile</code>&#xA0;is used with&#xA0;<code>leading</code>&#xA0;and&#xA0;<code>title</code>&#xA0;used to specify the location of the views:</p>



<pre class="wp-block-code"><code>  ListTile getNameInputListTile() {
    // TODO #12: Implement Name Section
    return ListTile(
      leading: Padding(
        padding: EdgeInsets.only(left: 8.0, top: 16.0),
        child: Text(&apos;Your Name:&apos;, style: Theme.of(context).textTheme.subtitle),
      ),
      title: Padding(
        padding: EdgeInsets.only(top: 10.0),
        child: Theme(
          data: ThemeData(
            primaryColor: kRegistrationBlack,
            primaryColorDark: kRegistrationBlack,
          ),
          child: Container(
            height: 40.0,
            child: TextField(
              style: Theme.of(context).textTheme.subtitle,
              controller: _nameTextController,
              textCapitalization: TextCapitalization.words,
              decoration: InputDecoration(
                fillColor: kRegistrationBlack,
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(5.0),
                ),
                contentPadding:
                    EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
                suffixIcon: IconButton(
                  icon: Icon(
                    Icons.clear,
                    color: kRegistrationBlack,
                  ),
                  onPressed: () {
                    _nameTextController.clear();
                  },
                ),
                hintText: NAME_HINT_TEXT,
                labelText: NAME_LABEL_TEXT,
              ),
            ),
          ),
        ),
      ),
    );
  }</code></pre>



<p>I will not go into further explanation here as bulks of the code are the same. You could challenge yourself by placing them in a centralised class like how I did it for&#xA0;<code>MomentsButton</code>, give it a custom initiliser and call it to reduce code.</p>



<h3 class="wp-block-heading">Guests Counter</h3>



<p>The counter section contains a label text, a <code>-</code> button, a counter text and a <code>+</code> button:</p>



<pre class="wp-block-code"><code>  Widget getGuestsCounter() {
    // TODO #13: Add Guest Counter
    return ListTile(
      leading: Padding(
        padding: EdgeInsets.only(left: 8.0, top: 8.0),
        child: Text(&apos;No. of Guests (Including yourself):&apos;,
            style: Theme.of(context).textTheme.subtitle),
      ),
      title: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: &lt;Widget&gt;[
          IconButton(
            color: kRegistrationBlack,
            icon: Icon(Icons.remove),
            onPressed: () {
              if (_guestsCounter &gt; 0) {
                setState(() =&gt; _guestsCounter--);
                _formData[&apos;guests&apos;] = _guestsCounter;
              }
            },
          ),
          Text(
            _guestsCounter.toString(),
            style: Theme.of(context).textTheme.title,
          ),
          IconButton(
            color: kRegistrationBlack,
            icon: Icon(Icons.add),
            onPressed: () {
              if (_guestsCounter &lt; 9) {
                setState(() =&gt; _guestsCounter++);
                _formData[&apos;guests&apos;] = _guestsCounter;
              }
            },
          ),
        ],
      ),
    );
  }</code></pre>



<p style="text-align:left">As you have understood how a&#xA0;<code>ListTile</code>&#xA0;works, the&#xA0;<code>leading</code>&#xA0;view is the label, where as the&#xA0;<code>title</code>&#xA0;view contains a&#xA0;<code>Row</code>which contains:</p>



<ul><li>IconButton (-)</li><li>Text</li><li>IconButton (+)</li></ul>



<h3 class="wp-block-heading">Section Header</h3>



<p>In every section, we are also giving it a nice header:</p>



<pre class="wp-block-code"><code>  Widget getSectionHeader(String title) {
    // TODO #14: Add Section Header
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: &lt;Widget&gt;[
        Padding(
          padding: EdgeInsets.only(top: 18, left: 22.0),
          child: Text(
            title,
            style: Theme.of(context).textTheme.headline,
          ),
        ),
        Padding(
          padding: EdgeInsets.only(left: 18, right: 18),
          child: Divider(
            color: kYankeesBlue,
          ),
        )
      ],
    );
  }</code></pre>



<h3 class="wp-block-heading">Gender Radio Option</h3>



<p>This is radio button type option, so go ahead and add this:</p>



<pre class="wp-block-code"><code>  Widget getGenderOptions() {
    // TODO #15: Add Gender Options
    return ListTile(
      leading: Padding(
        padding: EdgeInsets.only(left: 8.0, top: 4.0),
        child: Text(&apos;Gender:&apos;, style: Theme.of(context).textTheme.subtitle),
      ),
      title: Row(
        mainAxisAlignment: MainAxisAlignment.start,
        children: &lt;Widget&gt;[
          Radio(
            activeColor: kRegistrationBlack,
            value: 0,
            groupValue: _formData[&apos;gender&apos;] as int,
            onChanged: _handleGenderChange,
          ),
          Text(
            GENDER_CHOICES[0],
            style: Theme.of(context).textTheme.subtitle,
          ),
          Radio(
            value: 1,
            activeColor: kRegistrationBlack,
            groupValue: _formData[&apos;gender&apos;] as int,
            onChanged: _handleGenderChange,
          ),
          Text(
            GENDER_CHOICES[1],
            style: Theme.of(context).textTheme.subtitle,
          ),
        ],
      ),
    );
  }</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>In Visual Studio Code, you can actually use OPTION+SHIFT+F to perform an auto-indentation.</p></blockquote>



<p>Up to this point, I believe you are already a <code>ListTile</code> expert. Here we introduced <a href="https://api.flutter.dev/flutter/material/Radio-class.html?ref=appcoda.com">Radio</a>.</p>



<h3 class="wp-block-heading">Transport Checkbox Option</h3>



<p>The last option type is <a href="https://api.flutter.dev/flutter/material/Checkbox-class.html?ref=appcoda.com">Checkbox</a>:</p>



<pre class="wp-block-code"><code>  Widget getBusServiceOption() {
    // TODO #16: Add Transport Options
        return Padding(
      padding: EdgeInsets.only(bottom: 12),
      child: ListTile(
        leading: Checkbox(
          activeColor: kRegistrationBlack,
          onChanged: _handleTransportOption,
          value: _formData[&apos;bus&apos;] as bool,
        ),
        title: InkWell(
          onTap: () {
            setState(() {
              _formData[&apos;bus&apos;] = !_formData[&apos;bus&apos;];
            });
          },
          child: Text(
            &apos;I need transport&apos;,
            style: Theme.of(context).textTheme.subtitle,
          ),
        ),
      ),
    );
  }</code></pre>



<p>Nothing really special here, we used&#xA0;<code>InkWell</code>&#xA0;to improve the tap area of the&#xA0;<code>Checkbox</code>.</p>



<h3 class="wp-block-heading">Alert Dialog</h3>



<p>For the alert dialog, you may have already seen how an&#xA0;<code>AlertDialog</code>&#xA0;is created. Here&#x2019;s a simple dialog you should add to validate user&#x2019;s input:</p>



<pre class="wp-block-code"><code>  void _showDialog(String title, String content) {
    // TODO #11: Implement Dialog
    showDialog&lt;AlertDialog&gt;(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(title),
          content: Text(content),
          actions: &lt;Widget&gt;[
            FlatButton(
              child: Text(ALERT_OK),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }</code></pre>



<p>Lastly, the <code>Submit Button</code> which you are implemented it for the third time:</p>



<pre class="wp-block-code"><code>  Widget getSubmitButton() {
    // TODO #17: Add Submit Button
    return Padding(
      child: Center(
        child:
            MomentsButton(text: SUBMIT, action: _submitForm).getButton(context),
      ),
      padding: EdgeInsets.only(bottom: 16),
    );
  }</code></pre>



<p>Let the views assemble! Take a look at&#xA0;<code>renderForm</code>&#xA0;and you can see how we can render the form and order of each section easily! Here, the&#xA0;<code>build</code>&#xA0;function is completed for you so go ahead and run the app!</p>



<p>Try submitting the form without a name, you should be prompted with the <code>AlertDialog</code> you added. </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p>If you are unable to see your page rendered, try to delete the app and perform a fresh installation. Sometimes, flutter may unknowingly cache it.</p></blockquote>



<h2 class="wp-block-heading">List Screen</h2>



<p>Displaying a&#xA0;<code>List</code>&#xA0;of items is also a common feature of every app that we use.&#xA0;Headover to&#xA0;<code>item_list.dart</code>&#xA0;and here, you will use&#xA0;<code>ListView</code>&#xA0;to build a list of data:</p>



<pre class="wp-block-code"><code>  Widget _buildItemList() {
    // TODO #18: Implement Item List
    return ListView.builder(
      itemBuilder: (BuildContext context, int index) {
        return Column(
          children: &lt;Widget&gt;[
            Padding(
              child: ListTile(
                title: Text(
                  _itemList[index].title,
                  style: Theme.of(context).textTheme.title,
                ),
                subtitle: Text(_itemList[index].subtitle,
                    style: Theme.of(context).textTheme.subtitle),
              ),
              padding: EdgeInsets.all(10.0),
            ),
            Divider(
              height: 5.0,
            )
          ],
        );
      },
      itemCount: _itemList.length,
    );
  }</code></pre>



<p>The data has been pre-loaded from&#xA0;<code>scoped-models/item_list.dart</code>. The&#xA0;<code>builder</code>&#xA0;method in&#xA0;<code>ListView</code>&#xA0;automatically helps you iterate through the data&#xA0;<code>List</code>, so you can implement the rendering logic in&#xA0;<code>itemBuilder</code>. The&#xA0;<code>build</code>&#xA0;function has been implemented for you. Go ahead and run the app, you should see a nice scrolling view in&#xA0;<strong>List</strong>&#xA0;tab &#x1F642;</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="414" height="896" src="https://www.appcoda.com/content/images/wordpress/2019/08/app5.png" alt="Building a Flutter App with Complex UI" class="wp-image-17065" srcset="https://www.appcoda.com/content/images/wordpress/2019/08/app5.png 414w, https://www.appcoda.com/content/images/wordpress/2019/08/app5-200x433.png 200w, https://www.appcoda.com/content/images/wordpress/2019/08/app5-139x300.png 139w, https://www.appcoda.com/content/images/wordpress/2019/08/app5-400x866.png 400w, https://www.appcoda.com/content/images/wordpress/2019/08/app5-50x108.png 50w" sizes="(max-width: 414px) 100vw, 414px"></figure></div>



<h2 class="wp-block-heading">Rich List Screen</h2>



<p>The last and final screen is the&#xA0;<strong>RichList</strong>&#xA0;screen. I personally named it as&#xA0;<strong>RichList</strong>&#xA0;because it has an image and a customised look. Headover to&#xA0;<code>rich_list.dart</code>&#xA0;and you should already see everything implemented for you. But, you are seeing an empty screen because each card view is not implemented yet.</p>



<p>Now go to <code>rich_list_item_card.dart</code> and here is where all the wires are missing. You will be giving each image a circular frame, so go ahead and add these in <code>itemImage</code>:</p>



<pre class="wp-block-code"><code>  Widget get itemImage {
    // TODO #19: Implement List Item Image View
    return Container(
      width: 125.0,
      height: 125.0,
      decoration: BoxDecoration(
        border: Border.all(color: kPlatinum),
        shape: BoxShape.circle,
        image: DecorationImage(
          fit: BoxFit.cover,
          image: AssetImage(item.imagePath),
        ),
      ),
    );
  }</code></pre>



<p>Every image is also accompanied by a Card with description on the right:</p>



<pre class="wp-block-code"><code>  Widget get listItemCard {
    // TODO #20: Implement List Item Card View
    return Padding(
      padding: EdgeInsets.only(top: 18, bottom: 16),
      child: Container(
        constraints: BoxConstraints(minWidth: 300),
        height: 130.0,
        child: Card(
          elevation: 0.0,
          shape: RoundedRectangleBorder(
            side: BorderSide(color: kPlatinum, width: 1.0),
            borderRadius: BorderRadius.circular(4.0),
          ),
          color: Colors.white,
          child: Padding(
            padding: EdgeInsets.only(
              top: 10.0,
              bottom: 8.0,
              left: 95.0,
            ),
            child: Padding(
              padding: EdgeInsets.only(top: 8),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: &lt;Widget&gt;[
                  Text(widget.item.name,
                      style: Theme.of(context).textTheme.title),
                  Text(widget.item.description,
                      style: Theme.of(context).textTheme.subtitle),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }</code></pre>



<p>And finally, let&#x2019;s combine both into&#xA0;<code>build</code>&#xA0;function:</p>



<pre class="wp-block-code"><code>  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
      // TODO #21: Implement List Item Image Card View
      child: Container(
        height: 150.0,
        child: Stack(
          children: &lt;Widget&gt;[
            Positioned(
              left: 45.0,
              child: listItemCard,
            ),
            Positioned(top: 20.5, child: itemImage),
          ],
        ),
      ),
    );
  }</code></pre>



<p>While&#xA0;<code>Column</code>&#xA0;and&#xA0;<code>Row</code>&#xA0;help you to layer the views vertically down and horizontally across,&#xA0;<a href="https://api.flutter.dev/flutter/widgets/Stack-class.html?ref=appcoda.com">Stack</a>&#xA0;helps you to layer your views on top of each other. Here, the image overlaps the Card View by putting it in the second postion.&#xA0;</p>



<p>Run the app and you should see the completed RichList!</p>



<div class="wp-block-image"><figure class="aligncenter"><img loading="lazy" decoding="async" width="414" height="896" src="https://www.appcoda.com/content/images/wordpress/2019/08/app6.png" alt="Building a Flutter App with Complex UI" class="wp-image-17066" srcset="https://www.appcoda.com/content/images/wordpress/2019/08/app6.png 414w, https://www.appcoda.com/content/images/wordpress/2019/08/app6-200x433.png 200w, https://www.appcoda.com/content/images/wordpress/2019/08/app6-139x300.png 139w, https://www.appcoda.com/content/images/wordpress/2019/08/app6-400x866.png 400w, https://www.appcoda.com/content/images/wordpress/2019/08/app6-50x108.png 50w" sizes="(max-width: 414px) 100vw, 414px"></figure></div>



<h2 class="wp-block-heading">Moving Forward</h2>



<p>You can download the finished project <a href="https://github.com/lawreyios/FlutterMoments/tree/final_project?ref=appcoda.com">here</a>. You have learnt a lot about creating more complex UIs in this tutorial using Flutter. Flutter is natively developed by Google so it will generally have better performance on Android devices. However, given its natively-compiled capability, it actually runs smoothly on most iOS devices as well. </p>



<p>Flutter is still at its infant stage, and it surely has a very bright future. It can help you create beautiful and complex UIs with lesser code. I encourage you to use its <a href="https://flutter.dev/docs?ref=appcoda.com">documentation</a> diligently to build your own flavor of apps. </p>



<p>Thank you for following through this tutorial!</p>

<!--kg-card-end: html-->
]]></content:encoded></item><item><title><![CDATA[How to Detect and Track the User's Face Using ARKit]]></title><description><![CDATA[<!--kg-card-begin: html-->

<p>One of the most innovative inventions Apple has come up with in the past year is its True Depth camera. An ode to hardware and software engineers, the <a href="https://www.extremetech.com/mobile/255771-apple-iphone-x-truedepth-camera-works?ref=appcoda.com">True Depth camera</a> is what powers its secure facial recognition system, FaceID. As developers, the True Depth camera opens up a world</p>]]></description><link>https://www.appcoda.com/arkit-face-tracking/</link><guid isPermaLink="false">66612a0f166d3c03cf0114a7</guid><category><![CDATA[ARKit]]></category><category><![CDATA[Swift]]></category><category><![CDATA[iOS Programming]]></category><dc:creator><![CDATA[Sai Kambampati]]></dc:creator><pubDate>Wed, 31 Jul 2019 11:07:53 GMT</pubDate><media:content url="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1.png" medium="image"/><content:encoded><![CDATA[
<!--kg-card-begin: html-->

<img src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1.png" alt="How to Detect and Track the User&apos;s Face Using ARKit"><p>One of the most innovative inventions Apple has come up with in the past year is its True Depth camera. An ode to hardware and software engineers, the <a href="https://www.extremetech.com/mobile/255771-apple-iphone-x-truedepth-camera-works?ref=appcoda.com">True Depth camera</a> is what powers its secure facial recognition system, FaceID. As developers, the True Depth camera opens up a world of possibilities for us, especially in the field of face-base interactions.</p>



<p>Before we begin this ARKit tutorial, let me quickly brief you on the different parts of the camera. Like most iPhone/iPad front cameras, the True Depth camera comes with a microphone, a 7 megapixel camera, an ambient light sensor, a proximity sensor, and a speaker. What makes the True Depth camera itself is the addition of a dot projector, flood illuminator, and infrared camera.</p>



<p>The dot projector projects more than 30,000 invisible dots onto your face to build a local map (you&#x2019;ll see this later in the tutorial). The infrared camera reads the dot pattern, captures an infrared image, then sends the data to the Secure&#xA0;Enclave in the A12&#xA0;Bionic chip to confirm a&#xA0;match. Finally, the flood illuminator allowed invisible infrared light to identify your face even when it&#x2019;s dark. </p>



<p>These parts come together to create some magical experiences like Animojis and Memojis. Special effects that require a 3D model of the user&#x2019;s face and head can rely on the True Depth Camera.</p>



<h2 class="wp-block-heading">Introduction to the Demo Project</h2>



<p>I believe that it&#x2019;s important for developers to learn how to utilize the True Depth camera so they can perform face tracking and create amazing face-based experiences for users. In this tutorial, I will show you how we can use the 30,000 dots to recognize different facial movements using <code>ARFaceTrackingConfiguration</code>, that comes with the ARKit framework.</p>



<p>The final result will look like this:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="461" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-1024x461.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16989" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-1024x461.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-200x90.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-600x270.png 600w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-768x345.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-1680x756.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-1240x558.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-860x387.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-680x306.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-400x180.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-1-50x22.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Let&#x2019;s get started!</p>



<p>You will need to run this project on either an iPhone X, XS, XR, or iPad Pro (3rd gen). This is because these are the only devices which have the True Depth camera. We will also be using Swift 5 and Xcode 10.2.</p>



<p><strong>Editor&#x2019;s Note</strong>: If you&#x2019;re new to ARKit, you can refer to <a href="https://www.appcoda.com/arkit-3d-object/">our ARKit tutorials</a>.</p>



<h2 class="wp-block-heading">Creating a ARKit Demo for Face Tracking</h2>



<p>First, open Xcode and create a new Xcode project. Under templates, make sure to choose Augmented Reality App under iOS.</p>



<p>Next, set the name of your project. I simply named mine <em>True Depth</em>. Make sure the language is set to <em>Swift</em> and Content Technology to <em>SceneKit</em>.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="607" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-1024x607.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16990" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-1024x607.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-200x119.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-506x300.png 506w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-768x455.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-1240x735.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-860x510.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-680x403.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-400x237.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-3.png 1552w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Head over to <code>Main.storyboard</code>. There should be a single view with an <code>ARSCNView</code> already connected to an outlet in your code.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="607" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-1024x607.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16991" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-1024x607.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-200x119.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-506x300.png 506w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-768x455.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-1240x735.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-860x510.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-680x403.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-400x237.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-4.png 1552w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>What we have to do is really simple. All we need to do is add a <code>UIView</code> and a <code>UILabel</code> inside that view. This label will inform the user of the face expressions they are making.</p>



<p>Drag and drop a <code>UIView</code> into the <code>ARSCNView</code>. Now, let&#x2019;s set the constraints. Set the width to 240pt and height to 120pt. Set the left and bottom constraints to 20pt.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="607" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-1024x607.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16992" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-1024x607.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-200x119.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-506x300.png 506w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-768x455.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-1240x735.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-860x510.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-680x403.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-400x237.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-5.png 1552w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>For design purpose, let&#x2019;s set the alpha of the view to <em>0.8</em>. Now, drag a <code>UILabel</code> into the view you just added. Set the constraints to<em> 8 points</em> all around as shown below.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="576" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-1024x576.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16993" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-1024x576.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-200x113.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-533x300.png 533w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-768x432.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-1240x698.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-860x484.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-680x383.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-400x225.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6-50x28.png 50w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-6.png 1440w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Finally, set the alignment of the label to centralized. Your final storyboard should look like this. </p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="607" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-1024x607.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16994" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-1024x607.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-200x119.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-506x300.png 506w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-768x455.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-1240x735.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-860x510.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-680x403.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-400x237.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-7.png 1552w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Now, let&#x2019;s set the <code>IBOutlets</code> to our <code>ViewController.swift</code> file. Switch to the Assistant editor. Control and click on the <code>UIView</code> and <code>UILabel</code> and drag it over to <code>ViewController.swift</code> to create the <code>IBOutlets</code>.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="607" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-1024x607.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16995" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-1024x607.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-200x119.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-506x300.png 506w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-768x455.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-1240x735.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-860x510.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-680x403.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-400x237.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-8.png 1552w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>You should create two outlets: <code>faceLabel</code> and <code>labelView</code>. </p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="607" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-1024x607.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16996" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-1024x607.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-200x119.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-506x300.png 506w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-768x455.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-1240x735.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-860x510.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-680x403.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-400x237.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-9.png 1552w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading">Creating a Face Mesh</h2>



<p>Let&#x2019;s clean up the code a little bit. Because we chose the Augmented Reality App as our template, there&#x2019;s some code which we don&#x2019;t need. Change your <code>viewDidLoad</code> function to this:</p>



<pre class="wp-block-code"><code>override func viewDidLoad() {
    super.viewDidLoad()

    // 1 
    labelView.layer.cornerRadius = 10

    sceneView.delegate = self
    sceneView.showsStatistics = true

    // 2
    guard ARFaceTrackingConfiguration.isSupported else {
        fatalError(&quot;Face tracking is not supported on this device&quot;)
    }
}</code></pre>



<p>With the template, our code loads a 3D scene. However, we don&#x2019;t need this scene, so we delete it. At this point, you can delete the <code>art.scnassets</code> folder in the project navigator. Finally, we add two pieces of code to our <code>viewDidLoad</code> method.</p>



<ol><li>First, we round the corners of the <code>labelView</code>. This is more of a design choice. </li><li>Next, we check to see if the device supports the <code>ARFaceTrackingConfiguration</code>. This is the AR tracking setting we&#x2019;ll be using to create a face mesh. If we don&#x2019;t check to see if a device supports this, our app will crash. If the device does not support the configuration, then we will present an error.</li></ol>



<p>Next, we&#x2019;ll change one line in our <code>viewWillAppear</code> function. Change the constant <code>configuration</code> to <code>ARFaceTrackingConfiguration()</code>. Your code should look like this now.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="607" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-1024x607.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16997" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-1024x607.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-200x119.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-506x300.png 506w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-768x455.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-1240x735.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-860x510.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-680x403.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-400x237.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-10.png 1552w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>Next, we need to add the <code>ARSCNViewDelegate</code> methods. Add the following code below <code>// MARK: - ARSCNViewDelegate</code>. </p>



<pre class="wp-block-code"><code>func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -&gt; SCNNode? {
    let faceMesh = ARSCNFaceGeometry(device: sceneView.device!)
    let node = SCNNode(geometry: faceMesh)
    node.geometry?.firstMaterial?.fillMode = .lines
    return node
}</code></pre>



<p>This code runs when the <code>ARSCNView</code> is rendered. First, we create a face geometry of the <code>sceneView</code> and set it to the constant <code>faceMesh</code>. Then, we assign this geometry to an <code>SCNNode</code>. Finally, we set the material of the <code>node</code>. For most 3D objects, the material is usually the color or texture of a 3D object.</p>



<p>For the face mesh, you can use two materials- either a fill material or a lines material. I prefer the lines which is why I set <code>fillMode = .lines</code>, but you can use what you prefer. Your code should look like this now.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="607" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-1024x607.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16998" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-1024x607.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-200x119.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-506x300.png 506w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-768x455.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-1240x735.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-860x510.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-680x403.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-400x237.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11-50x30.png 50w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-11.png 1552w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<p>If we run the app, you should see something like this.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="743" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-1024x743.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-16999" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-1024x743.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-200x145.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-414x300.png 414w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-768x557.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-1680x1219.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-1240x900.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-860x624.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-680x493.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-400x290.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-12-50x36.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading">Updating the Face Mesh</h2>



<p>You may notice that the mesh does not update when you change your facial features (blinking, smiling, yawning, etc.). This is because we need to add the <code>renderer(_didUpdate:)</code> under the <code>renderer(_nodeFor)</code> method.</p>



<pre class="wp-block-code"><code>func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    if let faceAnchor = anchor as? ARFaceAnchor, let faceGeometry = node.geometry as? ARSCNFaceGeometry {
        faceGeometry.update(from: faceAnchor.geometry)
    }
}</code></pre>



<p>This code runs every time the <code>sceneView</code> updates. First, we define a <code>faceAnchor</code> as the anchor for the face it detects in the <code>sceneView</code>. The achor is the information about the pose, topology, and expression of a face detected in the face-tracking AR session. We also define the constant <code>faceGeometry</code> which is a topology of the face detected. Using these two constants we update the <code>faceGeometry</code> every time.</p>



<p>Run the code again. Now, you&#x2019;ll see the mesh updating every time you change your facial features, all running at 60 fps.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="694" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-1024x694.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-17000" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-1024x694.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-200x136.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-442x300.png 442w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-768x521.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-1680x1139.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-1240x841.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-860x583.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-680x461.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-400x271.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-14-50x34.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading">Analyzing the features</h2>



<p>First, let&#x2019;s create a variable at the top of the file.</p>



<pre class="wp-block-code"><code>var analysis = &quot;&quot;</code></pre>



<p>Next, type the following function at the end of the file.</p>



<pre class="wp-block-code"><code>func expression(anchor: ARFaceAnchor) {
    // 1
    let smileLeft = anchor.blendShapes[.mouthSmileLeft]
    let smileRight = anchor.blendShapes[.mouthSmileRight]
    let cheekPuff = anchor.blendShapes[.cheekPuff]
    let tongue = anchor.blendShapes[.tongueOut]
    self.analysis = &quot;&quot;

    // 2    
    if ((smileLeft?.decimalValue ?? 0.0) + (smileRight?.decimalValue ?? 0.0)) &gt; 0.9 {
        self.analysis += &quot;You are smiling. &quot;
    }

    if cheekPuff?.decimalValue ?? 0.0 &gt; 0.1 {
        self.analysis += &quot;Your cheeks are puffed. &quot;
    }

    if tongue?.decimalValue ?? 0.0 &gt; 0.1 {
        self.analysis += &quot;Don&apos;t stick your tongue out! &quot;
    }
}</code></pre>



<p>The above function takes an <code>ARFaceAnchor</code> as a parameter. </p>



<ol><li>The <code>blendShapes</code> are a dictionary of named coefficients representing the detected facial expression in terms of the movement of specific facial features. Apple provides over 50 coefficients which detect various different facial features. For our purpose we&#x2019;re using only 4: <code>mouthSmileLeft</code>, <code>mouthSmileRight</code>, <code>cheekPuff</code>, and <code>tongueOut</code>.</li><li>We take the coefficients and check the probability of the face performing these facial features. For detecting a smile, we add the probabilities of both the right and left side of the mouth. I found that the 0.9 for the smile and 0.1 for the cheek and tongue work best.</li></ol>



<p>We take the possible values and add the text to the <code>analysis</code> string.</p>



<p>Now that we have our function created, let&#x2019;s update our <code>renderer(_didUpdate:)</code> method.</p>



<pre class="wp-block-code"><code>func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    if let faceAnchor = anchor as? ARFaceAnchor, let faceGeometry = node.geometry as? ARSCNFaceGeometry {
        faceGeometry.update(from: faceAnchor.geometry)
        expression(anchor: faceAnchor)
        
        DispatchQueue.main.async {
            self.faceLabel.text = self.analysis
        }
        
    }
}</code></pre>



<p>We run the <code>expression</code> method every time the <code>sceneView</code> is updated. Since the function is setting the <code>analysis</code> string, we can finally set the text of the <code>faceLabel</code> to the <code>analysis</code> string.</p>



<p>Now, we&#x2019;re all done coding! Run the code and you should get the same result as we saw in the beginning.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="743" src="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-1024x743.png" alt="How to Detect and Track the User&apos;s Face Using ARKit" class="wp-image-17001" srcset="https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-1024x743.png 1024w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-200x145.png 200w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-414x300.png 414w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-768x557.png 768w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-1680x1219.png 1680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-1240x900.png 1240w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-860x624.png 860w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-680x493.png 680w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-400x290.png 400w, https://www.appcoda.com/content/images/wordpress/2019/07/facial-recognition-17-50x36.png 50w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>



<h2 class="wp-block-heading">Conclusion</h2>



<p>There is a lot of potential behind developing face-based experiences using ARKit. Games and apps can utilize the True Depth camera for a variety of purposes. One of my favorite apps is <a href="https://www.usehawkeye.com/?ref=appcoda.com">Hawkeye Access</a>, a browser you can control using your eyes.</p>



<p>For more information on the True Depth camera, you can check out Apple&#x2019;s video <a href="https://developer.apple.com/videos/play/tech-talks/601/?ref=appcoda.com">Face Tracking with ARKit</a>. You can download the final project <a href="https://github.com/appcoda/Face-Mesh?ref=appcoda.com">here</a>.</p>

<!--kg-card-end: html-->
]]></content:encoded></item></channel></rss>