<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ ios app development - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ ios app development - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 30 May 2026 16:31:26 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/ios-app-development/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build Secure iOS Apps in Swift: Common Security Pitfalls and How to Fix Them ]]>
                </title>
                <description>
                    <![CDATA[ These days, there are many ways attackers can try to compromise your applications. And thanks to the continued increase in cyberattacks, the demand for secure mobile applications – and by extension, secure coding – has never been higher. So if you’re... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-secure-ios-apps-in-swift-common-security-pitfalls-and-how-to-fix-them/</link>
                <guid isPermaLink="false">68ffdf1761d216440f5bb38a</guid>
                
                    <category>
                        <![CDATA[ Web Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Alex Tray ]]>
                </dc:creator>
                <pubDate>Mon, 27 Oct 2025 21:07:35 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761599240278/644f6ebb-6092-4ea0-99e3-a568bfb0390c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>These days, there are many ways attackers can try to compromise your applications. And thanks to the continued increase in cyberattacks, the demand for secure mobile applications – and by extension, secure coding – has never been higher.</p>
<p>So if you’re an iOS developer, you should also learn to prioritize security at every stage of app development.</p>
<p>Swift, Apple’s modern programming language, offers a wealth of tools and frameworks that simplify development while enhancing security, but only when used correctly.</p>
<p>This article explores 10 common security pitfalls in Swift-based iOS apps and offers practical strategies to mitigate them.</p>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>Before diving in, you’ll need:</p>
<ul>
<li><p>Working knowledge of Swift and iOS development.</p>
</li>
<li><p>Access to Xcode.</p>
</li>
<li><p>Basic understanding of how iOS apps communicate with servers.</p>
</li>
<li><p>Familiarity with Terminal/command line basics.</p>
</li>
</ul>
<p>The code examples are practical and explained step-by-step, making them accessible to junior developers while still offering value to experienced ones looking to strengthen their app's security.</p>
<h3 id="heading-what-well-cover">What we’ll cover:</h3>
<dl>
<ul>
<li><a href="" id="heading-what-are-the-most-prevalent-security-traps-in-swift-ios-applications">What are the Most Prevalent Security Traps in Swift iOS Applications?</a>
<ul>
<li><a href="" id="heading-1-insecure-data-storage">1. Insecure Data Storage</a></li>
<li><a href="" id="heading-2-weak-network-communication">2. Weak Network Communication</a></li>
<li><a href="" id="heading-3-improper-input-validation">3. Improper Input Validation</a></li>
<li><a href="" id="heading-4-hardcoding-secrets">4. Hardcoding Secrets</a></li>
<li><a href="" id="heading-5-insufficient-authentication-and-authorization">5. Insufficient Authentication and Authorization</a></li>
<li><a href="" id="heading-6-insecure-logging-and-error-handling">6. Insecure Logging and Error Handling</a></li>
<li><a href="" id="heading-7-ignoring-code-obfuscation-and-reverse-engineering">7. Ignoring Code Obfuscation and Reverse Engineering</a></li>
<li><a href="" id="heading-8-insecure-third-party-libraries">8. Insecure Third-Party Libraries</a></li>
<li><a href="" id="heading-9-insufficient-biometric-and-multi-factor-authentication">9. Insufficient Biometric and Multi-Factor Authentication</a></li>
<li><a href="" id="heading-10-disregarding-periodic-security-testing">10. Disregarding Periodic Security Testing</a></li>
</ul>
</li>
</ul>
</dl>

<h2 id="heading-what-are-the-most-prevalent-security-traps-in-swift-ios-applications"><strong>What are the Most Prevalent Security Traps in Swift iOS Applications?</strong></h2>
<p>Swift and iOS offer robust security features, but mistakes still happen. Following are the most common traps and how to fix them:</p>
<h3 id="heading-1-insecure-data-storage">1. Insecure Data Storage</h3>
<p>Among the most common mistakes developers make is having sensitive data stored insecurely. Passwords, tokens, or even individual user data can be left by accident in UserDefaults or local storage in unencrypted form. </p>
<p>While UserDefaults is convenient for small amounts of data, it is not secure for sensitive data as it is so easily accessible to attackers if the device is compromised.</p>
<h4 id="heading-how-to-fix">How to Fix:</h4>
<p>Use the Keychain Services API to securely store sensitive data. Keychain encrypts data and binds it to the device so that it can't be accessed by other unauthorized applications or users.</p>
<p>You can securely store credentials using libraries in Swift such as KeychainAccess or the built-in SecItemAdd and SecItemCopyMatching functions.</p>
<p>For example, this how you can store a user password in Keychain so as to ensure sensitive data is stored securely:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">do</span> {

<span class="hljs-keyword">try</span> keychain.<span class="hljs-keyword">set</span>(<span class="hljs-string">"userPassword123"</span>, key: <span class="hljs-string">"userPassword"</span>)

} <span class="hljs-keyword">catch</span> {

    <span class="hljs-built_in">print</span>(<span class="hljs-string">"Error saving to Keychain: \(error)"</span>)

}
</code></pre>
<p>Behind the scenes, here’s what happens when you call <code>keychain.set("userPassword123", key: "userPassword")</code> inside a KeychainManager class that uses Apple’s native Security framework for storage:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Security

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">KeychainManager</span> </span>{
 <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">set</span><span class="hljs-params">(<span class="hljs-number">_</span> value: String, key: String)</span></span> <span class="hljs-keyword">throws</span> {
     <span class="hljs-comment">// 1. Convert string to Data</span>
     <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> data = value.data(using: .utf8) <span class="hljs-keyword">else</span> {
         <span class="hljs-keyword">throw</span> <span class="hljs-type">NSError</span>(domain: <span class="hljs-string">"KeychainManager"</span>, code: -<span class="hljs-number">1</span>)
     }

     <span class="hljs-comment">// 2. Build the query dictionary</span>
     <span class="hljs-keyword">let</span> query: [<span class="hljs-type">String</span>: <span class="hljs-type">Any</span>] = [
         <span class="hljs-comment">// Store as password</span>
         kSecClass <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>: kSecClassGenericPassword,
         <span class="hljs-comment">// Your app's bundle identifier</span>
         kSecAttrService <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>: <span class="hljs-string">"com.yourapp.keychain"</span>,
         <span class="hljs-comment">// "userPassword"</span>
         kSecAttrAccount <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>: key,
         <span class="hljs-comment">// "userPassword123" encrypted</span>
         kSecValueData <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>: data,
         kSecAttrAccessible <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>: kSecAttrAccessibleAfterFirstUnlock
     ]
     <span class="hljs-comment">// 3. Save to keychain (iOS encrypts it automatically)</span>
     <span class="hljs-keyword">let</span> status = <span class="hljs-type">SecItemAdd</span>(query <span class="hljs-keyword">as</span> <span class="hljs-type">CFDictionary</span>, <span class="hljs-literal">nil</span>)
     <span class="hljs-comment">// 4. Check if successful</span>
     <span class="hljs-keyword">guard</span> status == errSecSuccess <span class="hljs-keyword">else</span> {
         <span class="hljs-keyword">throw</span> <span class="hljs-type">NSError</span>(domain: <span class="hljs-string">"KeychainManager"</span>, code: <span class="hljs-type">Int</span>(status))
     }
 }
}
</code></pre>
<p>When this function runs, iOS converts the string value, such as "userPassword123", into encrypted binary data and stores it securely in the device’s Keychain database. The entry is saved under the provided key (for example, "userPassword"), and only your app can access it.</p>
<p>Behind the scenes, the Keychain leverages strong security features, including hardware-backed encryption using device-specific keys, optional biometric protection through Face ID or Touch ID, and app-level isolation to ensure that no other app can read or modify your stored credentials.</p>
<h3 id="heading-2-weak-network-communication">2. Weak Network Communication</h3>
<p>Transmitting sensitive data over the network is another area prone to vulnerabilities. Using unencrypted HTTP connections exposes your app to man-in-the-middle (MITM) attacks, allowing attackers to intercept and modify data in transit.  </p>
<p><strong>The Problem</strong>: When data travels between your app and server over an insecure connection, attackers on the same network (like public Wi-Fi) can:</p>
<ul>
<li><p>Read sensitive information (passwords, personal data, payment details)</p>
</li>
<li><p>Modify requests and responses</p>
</li>
<li><p>Impersonate your legitimate server</p>
</li>
</ul>
<h4 id="heading-how-to-fix-1">How to Fix:</h4>
<p><strong>1. Always Use HTTPS</strong><br>HTTPS encrypts all data in transit, making it unreadable to attackers. iOS's App Transport Security (ATS) enforces this by blocking insecure HTTP connections by default:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// ❌ INSECURE - HTTP connection (blocked by ATS by default)</span>
<span class="hljs-keyword">let</span> url = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"http://api.example.com/login"</span>)

<span class="hljs-comment">// ✅ SECURE - HTTPS connection</span>
<span class="hljs-keyword">let</span> url = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"https://api.example.com/login"</span>)
</code></pre>
<p>You’ll want to avoid adding ATS exceptions to your Info.plist unless absolutely necessary. If a third-party API only supports HTTP, contact them to upgrade or find a more secure alternative.</p>
<p><strong>2. Implement Certificate Pinning (Advanced Protection)</strong></p>
<p>Even with HTTPS, your app could still be vulnerable to sophisticated MITM attacks. An attacker could install a fraudulent certificate on a user's device (through malware or social engineering), for example, and intercept HTTPS traffic that appears valid. The attacker's fake certificate would be trusted by the device, allowing them to decrypt and read "secure" communications.</p>
<p>Certificate pinning solves this by making your app trust only your specific server's certificate, rejecting all others – even if they're otherwise valid.</p>
<p><strong>How Certificate Pinning Works:</strong></p>
<p>Your app stores the expected certificate (or its public key hash) and validates it during each connection:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecureNetworkManager</span>: <span class="hljs-title">NSObject</span>, <span class="hljs-title">URLSessionDelegate</span> </span>{

    <span class="hljs-comment">// Store your server's certificate hash</span>
    <span class="hljs-comment">// Get this by running: openssl x509 -in certificate.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">let</span> expectedPublicKeyHash = <span class="hljs-string">"YOUR_CERTIFICATE_HASH_HERE"</span>

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">urlSession</span><span class="hljs-params">(
        <span class="hljs-number">_</span> session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping <span class="hljs-params">(URLSession.AuthChallengeDisposition, URLCredential?)</span></span></span> -&gt; <span class="hljs-type">Void</span>
    ) {
        <span class="hljs-comment">// Step 1: Check if this is a server trust challenge (certificate validation)</span>
        <span class="hljs-keyword">guard</span> challenge.protectionSpace.authenticationMethod == <span class="hljs-type">NSURLAuthenticationMethodServerTrust</span>,
              <span class="hljs-keyword">let</span> serverTrust = challenge.protectionSpace.serverTrust
        <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Not a certificate challenge; use default handling</span>
            completionHandler(.performDefaultHandling, <span class="hljs-literal">nil</span>)
            <span class="hljs-keyword">return</span>
        }

        <span class="hljs-comment">// Step 2: Validate that the server's certificate matches our pinned certificate</span>
        <span class="hljs-keyword">if</span> isValidServerTrust(serverTrust) {
            <span class="hljs-comment">// Certificate matches - proceed with the connection</span>
            completionHandler(.useCredential, <span class="hljs-type">URLCredential</span>(trust: serverTrust))
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Certificate doesn't match - reject the connection to prevent MITM attack</span>
            completionHandler(.cancelAuthenticationChallenge, <span class="hljs-literal">nil</span>)
        }
    }

    <span class="hljs-comment">// Validates the server's certificate against our pinned hash</span>
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isValidServerTrust</span><span class="hljs-params">(<span class="hljs-number">_</span> serverTrust: SecTrust)</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-comment">// Extract the server's certificate</span>
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> serverCertificate = <span class="hljs-type">SecTrustGetCertificateAtIndex</span>(serverTrust, <span class="hljs-number">0</span>) <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
        }

        <span class="hljs-comment">// Get the public key from the certificate</span>
        <span class="hljs-keyword">let</span> serverPublicKey = <span class="hljs-type">SecCertificateCopyKey</span>(serverCertificate)
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> publicKey = serverPublicKey <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
        }

        <span class="hljs-comment">// Convert the public key to data and hash it</span>
        <span class="hljs-keyword">var</span> error: <span class="hljs-type">Unmanaged</span>&lt;<span class="hljs-type">CFError</span>&gt;?
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> publicKeyData = <span class="hljs-type">SecKeyCopyExternalRepresentation</span>(publicKey, &amp;error) <span class="hljs-keyword">as</span> <span class="hljs-type">Data?</span> <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
        }

        <span class="hljs-comment">// Hash the public key using SHA-256</span>
        <span class="hljs-keyword">let</span> publicKeyHash = <span class="hljs-type">SHA256</span>.hash(data: publicKeyData)
        <span class="hljs-keyword">let</span> publicKeyHashString = <span class="hljs-type">Data</span>(publicKeyHash).base64EncodedString()

        <span class="hljs-comment">// Compare with our expected hash</span>
        <span class="hljs-keyword">return</span> publicKeyHashString == expectedPublicKeyHash
    }
}
</code></pre>
<p>What this code does, step-by-step:</p>
<ol>
<li><p><code>urlSession(_:didReceive:completionHandler:)</code> – This method is called whenever your app makes an HTTPS connection. iOS asks: "Should I trust this server's certificate?"</p>
</li>
<li><p>Check authentication method – We verify this is a server trust challenge (certificate validation), not some other type of authentication.</p>
</li>
<li><p>Validate the certificate – We call <code>isValidServerTrust()</code>, which:</p>
<ul>
<li><p>Extracts the server's certificate from the connection</p>
</li>
<li><p>Gets the public key from that certificate</p>
</li>
<li><p>Hashes the public key using SHA-256</p>
</li>
<li><p>Compares the hash to our stored, expected hash</p>
</li>
</ul>
</li>
</ol>
<ol start="4">
<li>Make a decision:</li>
</ol>
<ul>
<li><p>If hashes match, then the server is legitimate. Proceed with <code>.useCredential</code>.</p>
</li>
<li><p>If hashes don't match, we have a potential MITM attack. Cancel with <code>.cancelAuthenticationChallenge</code>.</p>
</li>
</ul>
<p>So how does this prevent MITM attacks? Even if an attacker installs a fraudulent certificate on the user's device and intercepts traffic, their certificate's hash won't match your pinned hash. Your app will reject the connection, preventing the attacker from decrypting your traffic.</p>
<p><strong>3. Additional Protection: Recommend a VPN on Public Wi-Fi</strong></p>
<p>You can also recommend that users connect through a VPN when on public Wi-Fi for an added layer of security, and provide guidance on <a target="_blank" href="https://surfshark.com/blog/how-to-use-a-vpn">how to use a VPN</a> effectively to keep their data safe.</p>
<p>For developers, maintaining strong app security also depends on having a well-optimized system, learning <a target="_blank" href="https://cleanmymac.com/blog/macos-tahoe-slow">how to speed up a slow Mac</a> can help ensure smoother builds, faster testing, and a more secure overall development workflow.</p>
<h3 id="heading-3-improper-input-validation">3. Improper Input Validation</h3>
<p>Some developers neglect correct input validation, leading to a number of vulnerabilities including SQL injection, remote code execution, and data corruption.</p>
<p>While Swift has strong typing support, some developers don’t sanitize user input or API responses. Incorporating real-time <a target="_blank" href="https://www.freecodecamp.org/news/how-to-use-email-validation-api-for-flask-user-authentication/">API email validation</a> ensures that users provide legitimate, properly formatted email addresses before they are stored or processed, reducing both security risks and data quality issues.</p>
<h4 id="heading-how-to-fix-2">How to Fix:</h4>
<p>Input validation is your first line of defense against malicious data. Here's how to protect your iOS applications:</p>
<p><strong>1. Validate User Input with Patterns</strong></p>
<p>Always validate user input using regular expressions or predefined patterns before processing. For example, when accepting email addresses:</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isValidEmail</span><span class="hljs-params">(<span class="hljs-number">_</span> email: String)</span></span> -&gt; <span class="hljs-type">Bool</span> {
    <span class="hljs-keyword">let</span> emailRegex = <span class="hljs-string">"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"</span>
    <span class="hljs-keyword">let</span> emailPredicate = <span class="hljs-type">NSPredicate</span>(format: <span class="hljs-string">"SELF MATCHES %@"</span>, emailRegex)
    <span class="hljs-keyword">return</span> emailPredicate.evaluate(with: email)
}

<span class="hljs-comment">// Only accept properly formatted data</span>
<span class="hljs-keyword">guard</span> isValidEmail(userEmail) <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Reject invalid input</span>
    <span class="hljs-keyword">return</span>
}
</code></pre>
<p>This ensures that only properly formatted data is accepted, preventing malformed or malicious input from entering your system.</p>
<p><strong>2. Sanitize API Responses</strong></p>
<p>Never trust external data. Always validate and sanitize API responses before using them:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> userAge = apiResponse[<span class="hljs-string">"age"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">Int</span>,
   userAge &gt;= <span class="hljs-number">0</span> &amp;&amp; userAge &lt;= <span class="hljs-number">150</span> {
    <span class="hljs-comment">// Safe to use</span>
    user.age = userAge
} <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Handle invalid data appropriately</span>
    <span class="hljs-keyword">throw</span> <span class="hljs-type">ValidationError</span>.invalidAge
}
</code></pre>
<p><strong>3. Use Parameterized Queries (Most Critical)</strong></p>
<p>The most dangerous mistake is building database queries through string concatenation. Consider this vulnerable code:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// ❌ NEVER DO THIS - Vulnerable to SQL Injection</span>
<span class="hljs-keyword">let</span> username = userInput  <span class="hljs-comment">// Could be: "admin' OR '1'='1"</span>
<span class="hljs-keyword">let</span> query = <span class="hljs-string">"SELECT * FROM users WHERE username = '\(username)'"</span>
database.execute(query)
</code></pre>
<p>If a malicious user enters admin' OR '1'='1 as their username, the query becomes:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> username = <span class="hljs-string">'admin'</span> <span class="hljs-keyword">OR</span> <span class="hljs-string">'1'</span>=<span class="hljs-string">'1'</span>
</code></pre>
<p>This would return all users in the database instead of just one, potentially exposing sensitive data. The secure solution uses parameterized queries:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// ✅ SAFE - Using parameterized queries</span>
<span class="hljs-keyword">let</span> query = <span class="hljs-string">"SELECT * FROM users WHERE username = ?"</span>
database.execute(query, withArgumentsIn: [username])
</code></pre>
<p>In this approach, the <code>?</code> is a placeholder that the database treats as a parameter, not as part of the SQL command. The username value is passed separately in the <code>withArgumentsIn</code> array.</p>
<p>This means that even if a user tries to inject SQL code like <code>admin' OR '1'='1</code>, the database will treat the entire string as a literal username to search for – not as executable SQL code. The database engine automatically escapes any special characters, completely eliminating the risk of SQL injection.</p>
<p>By separating the query structure from the data, parameterized queries ensure that user input can never alter the intended logic of your SQL statements.</p>
<h3 id="heading-4-hardcoding-secrets">4. Hardcoding Secrets</h3>
<p>API keys, credentials, or private tokens hard-coded in the source code is another serious security mistake. Attackers can extract such secrets from compiled binaries using reverse-engineering tools, especially for apps released to the public.</p>
<p>Once exposed, these credentials can be used to access your backend services, potentially leading to data breaches or unauthorized charges.</p>
<h4 id="heading-the-problem-hardcoded-secrets">The Problem – Hardcoded Secrets:</h4>
<pre><code class="lang-swift"><span class="hljs-comment">// NEVER DO THIS</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">APIClient</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">let</span> apiKey = <span class="hljs-string">"1234567890abcdef"</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">let</span> secretToken = <span class="hljs-string">"sk_live_51H..."</span>

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeRequest</span><span class="hljs-params">()</span></span> {
        <span class="hljs-comment">// These secrets are embedded in your binary</span>
        <span class="hljs-keyword">let</span> headers = [<span class="hljs-string">"Authorization"</span>: <span class="hljs-string">"Bearer \(apiKey)"</span>]
    }
}
</code></pre>
<p><strong>How to Fix:</strong></p>
<p>Never store sensitive credentials directly in your code. Here are secure alternatives:</p>
<p><strong>Solution 1: Fetch Secrets from Backend at Runtime</strong></p>
<p>The most secure approach is to never store secrets on the client at all. Instead, authenticate users and let your backend make authorized API calls:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">APIClient</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> sessionToken: <span class="hljs-type">String?</span>

    <span class="hljs-comment">// User logs in and receives a temporary session token</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">authenticateUser</span><span class="hljs-params">(email: String, password: String)</span></span> async <span class="hljs-keyword">throws</span> {
        <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">try</span> await backend.login(email: email, password: password)
        <span class="hljs-comment">// Store only a temporary, user-specific session token</span>
        <span class="hljs-keyword">self</span>.sessionToken = response.sessionToken
    }

    <span class="hljs-comment">// Backend handles the actual API calls with the real API key</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fetchUserData</span><span class="hljs-params">()</span></span> async <span class="hljs-keyword">throws</span> -&gt; <span class="hljs-type">UserData</span> {
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> token = sessionToken <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">throw</span> <span class="hljs-type">AuthError</span>.notAuthenticated
        }

        <span class="hljs-comment">// Your backend receives this request, validates the session token,</span>
        <span class="hljs-comment">// then uses its own API keys to fetch data from third-party services</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">try</span> await backend.getUserData(sessionToken: token)
    }
}
</code></pre>
<p><strong>How this works:</strong></p>
<p>Your app never knows the actual API keys. When a user needs data, your app sends a request to your own backend server with a session token. Your backend validates the token, then uses its own securely stored API keys to make the actual third-party API calls. This way, the real secrets never leave your server.</p>
<p><strong>Solution 2: Environment Variables or Config Files (Development Only)</strong></p>
<p>For development environments, use .xcconfig files that are excluded from version control:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// Secrets.xcconfig (add to .gitignore!)</span>
<span class="hljs-type">API_KEY</span> = your_dev_api_key_here
<span class="hljs-type">API_SECRET</span> = your_dev_secret_here

<span class="hljs-comment">// Access in your code through Info.plist</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Config</span> </span>{
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> apiKey: <span class="hljs-type">String</span> = {
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> key = <span class="hljs-type">Bundle</span>.main.object(forInfoDictionaryKey: <span class="hljs-string">"API_KEY"</span>) <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"API_KEY not found in configuration"</span>)
        }
        <span class="hljs-keyword">return</span> key
    }()
}
</code></pre>
<p><strong>Important</strong>: This approach is only suitable for non-production environments! Never ship production API keys with your app, even in config files.</p>
<h3 id="heading-5-insufficient-authentication-and-authorization">5. Insufficient Authentication and Authorization</h3>
<p>Relying on client-side authentication and authorization checks is risky. Attackers can cause the app to bypass these checks and access in an unauthorized way by brute forcing or tampering with the app/runtime.</p>
<h4 id="heading-how-to-fix-3">How to Fix:</h4>
<ul>
<li><p>Do authentication and authorization on the server side instead of the client-side.</p>
</li>
<li><p>Use JWT (JSON Web Tokens) or OAuth 2.0 for authenticated user login.</p>
</li>
<li><p>Token expiration and refresh logic needs to be implemented in order to minimize the likelihood of token theft.</p>
</li>
</ul>
<p><strong>Example: Securely sending JWT:</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> request = <span class="hljs-type">URLRequest</span>(url: apiURL)

request.setValue(<span class="hljs-string">"Bearer \(jwtToken)"</span>, forHTTPHeaderField: <span class="hljs-string">"Authorization"</span>)
</code></pre>
<h3 id="heading-6-insecure-logging-and-error-handling">6. Insecure Logging and Error Handling</h3>
<p>Extensive and insecure logging practices, as well as uncaught exceptions, can lead to the exposure of sensitive information including usernames, passwords, and API keys.</p>
<h4 id="heading-how-to-fix-4">How to Fix:</h4>
<ul>
<li><p>Log sensitive information carefully.</p>
</li>
<li><p>Implement controlled error management and provide the minimum amount of information in user-presented messages.</p>
</li>
<li><p>Implement secure logging libraries that mask or encrypt personal data.</p>
</li>
</ul>
<pre><code class="lang-swift"><span class="hljs-keyword">do</span> {
    <span class="hljs-keyword">try</span> someRiskyOperation()
} <span class="hljs-keyword">catch</span> {
    <span class="hljs-comment">// Log error securely</span>
    <span class="hljs-type">Logger</span>.log(<span class="hljs-string">"Operation failed: \(error.localizedDescription)"</span>)
}
</code></pre>
<h3 id="heading-7-ignoring-code-obfuscation-and-reverse-engineering">7. Ignoring Code Obfuscation and Reverse Engineering</h3>
<p>Swift binaries can be reverse-engineered to expose sensitive business logic, algorithms, or hidden secrets. Attackers use tools like Hopper Disassembler, class-dump, or IDA Pro to decompile your app and analyze how it works internally. This risk is often underestimated, especially for smaller apps, but any app can be a target.</p>
<p>This means that when you compile a Swift app, the resulting binary contains:</p>
<ul>
<li><p>Class names and method signatures</p>
</li>
<li><p>String literals (URLs, error messages, keys)</p>
</li>
<li><p>The structure of your code logic</p>
</li>
<li><p>Algorithm implementations</p>
</li>
</ul>
<p>An attacker can extract this information and use it to understand your app's authentication flow and bypass it, copy your proprietary algorithms, find hardcoded API endpoints or keys you thought were "hidden", discover premium features to unlock without paying, and so on.</p>
<p><strong>Why It's Bad – Real Example:</strong></p>
<p>Let's imagine you have a premium feature check in your app:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FeatureManager</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isPremiumUser</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-comment">// Check if user has premium access</span>
        <span class="hljs-keyword">let</span> hasSubscription = <span class="hljs-type">UserDefaults</span>.standard.bool(forKey: <span class="hljs-string">"premium_unlocked"</span>)
        <span class="hljs-keyword">return</span> hasSubscription
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">unlockPremiumFeature</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">guard</span> isPremiumUser() <span class="hljs-keyword">else</span> {
            showPaywall()
            <span class="hljs-keyword">return</span>
        }
        <span class="hljs-comment">// Show premium content</span>
        showPremiumContent()
    }
}
</code></pre>
<p>An attacker could reverse-engineer your app and discover that the method <code>isPremiumUser()</code> controls access, and that it simply checks a <code>UserDefaults</code> key called <code>premium_unlocked</code>. They would then know that they could use runtime manipulation tools to set this value to true, bypassing your paywall entirely.</p>
<p><strong>How to Fix:</strong></p>
<p><strong>1. Use Swift Compiler Optimizations</strong></p>
<p>Enable optimization flags that strip debugging symbols and make the binary harder to read:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// In your build settings:</span>
<span class="hljs-comment">// - Set "Optimization Level" to "-O" (or -Osize) for release builds</span>
<span class="hljs-comment">// - Enable "Strip Debug Symbols During Copy" = YES</span>
<span class="hljs-comment">// - Set "Strip Style" to "All Symbols"</span>
</code></pre>
<p>This removes function names and makes the compiled code less readable – though class/method names remain partially visible.</p>
<p><strong>2. Use Symbol Obfuscation Tools</strong></p>
<p>Tools like SwiftShield can rename your classes, methods, and properties to meaningless names:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// Before obfuscation (readable to attackers):</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FeatureManager</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isPremiumUser</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">Bool</span> { ... }
}

<span class="hljs-comment">// After obfuscation (harder to understand):</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">a7f3b2</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">x9k2m</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">Bool</span> { ... }
}
</code></pre>
<p>While this doesn't prevent reverse engineering, it makes it significantly harder for attackers to understand what the code does.</p>
<p><strong>3. Move Sensitive Logic to the Server (Best Practice)</strong></p>
<p>Instead of checking premium status locally, verify it server-side:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// ✅ Secure approach - Server validates everything</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FeatureManager</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">unlockPremiumFeature</span><span class="hljs-params">()</span></span> async {
        <span class="hljs-keyword">do</span> {
            <span class="hljs-comment">// Server checks if user truly has premium access</span>
            <span class="hljs-keyword">let</span> hasAccess = <span class="hljs-keyword">try</span> await backend.verifyPremiumAccess(userId: currentUserId)

            <span class="hljs-keyword">if</span> hasAccess {
                showPremiumContent()
            } <span class="hljs-keyword">else</span> {
                showPaywall()
            }
        } <span class="hljs-keyword">catch</span> {
            <span class="hljs-comment">// Handle error</span>
            showPaywall()
        }
    }
}
</code></pre>
<p><strong>How this works:</strong></p>
<p>Your backend maintains the source of truth about premium access. Even if an attacker reverse-engineers your app and tries to bypass the check, the server will reject unauthorized requests. The app becomes just a UI layer, while all critical decisions happen server-side – where attackers can't manipulate them.</p>
<p>The key principle is to assume your app code is public: never rely on client-side checks for security-critical operations like payments, access control, or authentication. Use obfuscation to make reverse engineering harder, but ultimately move sensitive logic to your secure backend</p>
<h3 id="heading-8-insecure-third-party-libraries">8. Insecure Third-Party Libraries</h3>
<p>Third-party libraries are at risk if they are hacked or outdated. Developers might inadvertently prioritize app functionality over potential security risks from dependencies, and <a target="_blank" href="https://airbyte.com/top-etl-tools-for-sources/etl-tools">ETL tools</a> can further help by streamlining the monitoring and processing of dependency-related data to identify vulnerabilities more efficiently.</p>
<p>On a broader scale, implementing strong data center security practices ensures that even if third-party components introduce risks, the underlying infrastructure remains resilient against attacks.</p>
<h4 id="heading-how-to-fix-5">How to Fix:</h4>
<ul>
<li><p>Use only high-quality, well-maintained libraries.</p>
</li>
<li><p>Update dependencies and monitor CVEs (Common Vulnerabilities and Exposures).</p>
</li>
<li><p>Audit library code if it handles sensitive data.</p>
</li>
</ul>
<h3 id="heading-9-insufficient-biometric-and-multi-factor-authentication">9. Insufficient Biometric and Multi-Factor Authentication</h3>
<p>Most applications rely on passwords alone, which are vulnerable to being hacked. Enabling biometrics like Face ID or Touch ID enhances security for users.</p>
<h4 id="heading-how-to-fix-6">How to Fix:</h4>
<ul>
<li><p>Tie LocalAuthentication framework for biometric authentication.</p>
</li>
<li><p>Combine biometrics with server-based authentication for multifactor authentication (MFA).</p>
</li>
</ul>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> LocalAuthentication

<span class="hljs-keyword">let</span> context = <span class="hljs-type">LAContext</span>()

<span class="hljs-keyword">var</span> error: <span class="hljs-type">NSError?</span>

<span class="hljs-keyword">if</span> context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &amp;error) {

    context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,

                        localizedReason: <span class="hljs-string">"Access your account"</span>) { success, authError <span class="hljs-keyword">in</span>

        <span class="hljs-type">DispatchQueue</span>.main.async {

         <span class="hljs-keyword">if</span> success {

                <span class="hljs-comment">// Proceed securely</span>

         } <span class="hljs-keyword">else</span> {

                <span class="hljs-comment">// Handle failure (authError may contain the reason)</span>

                <span class="hljs-built_in">print</span>(<span class="hljs-string">"Authentication failed: \(authError?.localizedDescription ?? "</span><span class="hljs-type">Unknown</span> error<span class="hljs-string">")"</span>)

         }

     }

}

} <span class="hljs-keyword">else</span> {

<span class="hljs-comment">// Biometrics not available, check error for details</span>

    <span class="hljs-built_in">print</span>(<span class="hljs-string">"Biometrics unavailable: \(error?.localizedDescription ?? "</span><span class="hljs-type">Unknown</span> error<span class="hljs-string">")"</span>)

}
</code></pre>
<h3 id="heading-10-disregarding-periodic-security-testing">10. Disregarding Periodic Security Testing</h3>
<p>Apps, despite following best practices during development, often contain unexplored vulnerabilities that emerge from complex interactions, third-party dependencies, or newly discovered attack vectors. Regular security testing is absolutely essential to discover these vulnerabilities before attackers exploit them.</p>
<p>Security testing should happen at multiple stages, using accessible tools and practices:</p>
<ol>
<li><p><strong>Automated security scans:</strong> Run automatically with every build to catch common issues.</p>
</li>
<li><p><strong>Self-conducted code audits:</strong> Regular security-focused reviews of your own code using established guidelines.</p>
</li>
<li><p><strong>Vulnerability scanning tools:</strong> Use free tools like MobSF to analyze your app for security flaws.</p>
</li>
<li><p><strong>Dependency audits:</strong> Checking third-party libraries for known security vulnerabilities.</p>
</li>
</ol>
<p><strong>How to Fix:</strong></p>
<p><strong>1. Implement Automated Security Scans in CI/CD</strong></p>
<p>Integrate security scanning tools into your continuous integration pipeline so every code change is automatically checked:</p>
<pre><code class="lang-swift"># <span class="hljs-type">Example</span>: <span class="hljs-type">GitHub</span> <span class="hljs-type">Actions</span> workflow <span class="hljs-keyword">for</span> automated security scanning
name: <span class="hljs-type">Security</span> <span class="hljs-type">Scan</span>

on: [push, pull_request]

jobs:
  security-scan:
    runs-on: macos-latest

    steps:
      - name: <span class="hljs-type">Checkout</span> code
        uses: actions/checkout@v3

      - name: <span class="hljs-type">Run</span> <span class="hljs-type">MobSF</span> <span class="hljs-type">Security</span> <span class="hljs-type">Scan</span>
        run: |
          # <span class="hljs-type">Mobile</span> <span class="hljs-type">Security</span> <span class="hljs-type">Framework</span> - scans <span class="hljs-keyword">for</span> common vulnerabilities
          docker run -v $(pwd):/app opensecurity/mobile-security-framework-mobsf

      - name: <span class="hljs-type">Dependency</span> <span class="hljs-type">Vulnerability</span> <span class="hljs-type">Check</span>
        run: |
          # <span class="hljs-type">Check</span> <span class="hljs-type">CocoaPods</span>/<span class="hljs-type">SPM</span> dependencies <span class="hljs-keyword">for</span> known <span class="hljs-type">CVEs</span>
          brew install dependency-check
          dependency-check --scan ./<span class="hljs-type">Podfile</span>.lock --format <span class="hljs-type">JSON</span>

      - name: <span class="hljs-type">Secret</span> <span class="hljs-type">Detection</span>
        run: |
          # <span class="hljs-type">Detect</span> accidentally committed secrets
          brew install truffleHog
          truffleHog filesystem . --json

      - name: <span class="hljs-type">Fail</span> build on critical issues
        run: |
          <span class="hljs-keyword">if</span> grep -q <span class="hljs-string">"CRITICAL"</span> security-report.json; then
            echo <span class="hljs-string">"Critical security issues found!"</span>
            exit <span class="hljs-number">1</span>
          fi
</code></pre>
<p><strong>Automated scans check for:</strong></p>
<ul>
<li><p>Hardcoded API keys, tokens, or passwords</p>
</li>
<li><p>Insecure network configurations (allowing HTTP instead of HTTPS)</p>
</li>
<li><p>Weak cryptographic algorithms</p>
</li>
<li><p>Known vulnerabilities in third-party libraries</p>
</li>
<li><p>Improper SSL/TLS certificate validation</p>
</li>
<li><p>Insecure data storage (storing sensitive data in UserDefaults)</p>
</li>
<li><p>Excessive app permissions</p>
</li>
</ul>
<p><strong>Example output from an automated scan:</strong></p>
<pre><code class="lang-swift"><span class="hljs-type">Security</span> <span class="hljs-type">Scan</span> <span class="hljs-type">Results</span>:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[<span class="hljs-type">CRITICAL</span>] <span class="hljs-type">Hardcoded</span> <span class="hljs-type">API</span> <span class="hljs-type">Key</span> <span class="hljs-type">Found</span>
  <span class="hljs-type">File</span>: <span class="hljs-type">APIClient</span>.swift:<span class="hljs-number">15</span>
  <span class="hljs-type">Issue</span>: <span class="hljs-type">API</span> key <span class="hljs-string">"sk_live_abc123..."</span> detected <span class="hljs-keyword">in</span> source code

[<span class="hljs-type">HIGH</span>] <span class="hljs-type">Insecure</span> <span class="hljs-type">HTTP</span> <span class="hljs-type">Connection</span>
  <span class="hljs-type">File</span>: <span class="hljs-type">NetworkManager</span>.swift:<span class="hljs-number">42</span>
  <span class="hljs-type">Issue</span>: <span class="hljs-type">App</span> allows cleartext <span class="hljs-type">HTTP</span> traffic to api.example.com
  <span class="hljs-type">Fix</span>: <span class="hljs-type">Enforce</span> <span class="hljs-type">HTTPS</span> or add exception to <span class="hljs-type">Info</span>.plist <span class="hljs-keyword">if</span> <span class="hljs-keyword">required</span>

[<span class="hljs-type">MEDIUM</span>] <span class="hljs-type">Weak</span> <span class="hljs-type">Encryption</span> <span class="hljs-type">Algorithm</span>
  <span class="hljs-type">File</span>: <span class="hljs-type">DataEncryption</span>.swift:<span class="hljs-number">28</span>
  <span class="hljs-type">Issue</span>: <span class="hljs-type">Using</span> <span class="hljs-type">MD5</span> <span class="hljs-keyword">for</span> hashing (cryptographically broken)
  <span class="hljs-type">Fix</span>: <span class="hljs-type">Use</span> <span class="hljs-type">SHA</span>-<span class="hljs-number">256</span> or better

[<span class="hljs-type">LOW</span>] <span class="hljs-type">Outdated</span> <span class="hljs-type">Dependency</span>
  <span class="hljs-type">Library</span>: <span class="hljs-type">Alamofire</span> <span class="hljs-number">4.2</span>.<span class="hljs-number">0</span>
  <span class="hljs-type">Issue</span>: <span class="hljs-type">Known</span> vulnerability <span class="hljs-type">CVE</span>-<span class="hljs-number">2021</span>-<span class="hljs-number">12345</span>
  <span class="hljs-type">Fix</span>: <span class="hljs-type">Update</span> to version <span class="hljs-number">5.6</span>.<span class="hljs-number">0</span> or later
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
<span class="hljs-type">Build</span> <span class="hljs-type">Failed</span>: <span class="hljs-number">2</span> critical issues must be fixed before deployment
</code></pre>
<p><strong>2. Use MobSF (Mobile Security Framework) for Vulnerability Analysis</strong></p>
<p>MobSF is a free, automated tool that analyzes your iOS app for security issues:</p>
<pre><code class="lang-swift"># <span class="hljs-type">Install</span> and run <span class="hljs-type">MobSF</span> locally
docker pull opensecurity/mobile-security-framework-mobsf
docker run -it -p <span class="hljs-number">8000</span>:<span class="hljs-number">8000</span> opensecurity/mobile-security-framework-mobsf

# <span class="hljs-type">Upload</span> your .ipa file through the web interface at localhost:<span class="hljs-number">8000</span>
# <span class="hljs-type">MobSF</span> will analyze and provide a detailed security report
</code></pre>
<p>What MobSF checks:</p>
<ul>
<li><p>Binary analysis for hardcoded secrets</p>
</li>
<li><p>Insecure data storage patterns</p>
</li>
<li><p>Weak cryptographic implementations</p>
</li>
<li><p>Insecure network connections</p>
</li>
<li><p>Code quality and security best practices</p>
</li>
<li><p>Compliance with security standards</p>
</li>
</ul>
<p><strong>3. Conduct Regular Code Audits Using OWASP MSTG</strong></p>
<p>Use the OWASP Mobile Security Testing Guide as a checklist to audit your own code:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// Example: Following OWASP MSTG recommendations for secure storage</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecureStorage</span> </span>{
    <span class="hljs-comment">// ❌ Insecure - UserDefaults is not encrypted</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">saveTokenInsecurely</span><span class="hljs-params">(<span class="hljs-number">_</span> token: String)</span></span> {
        <span class="hljs-type">UserDefaults</span>.standard.<span class="hljs-keyword">set</span>(token, forKey: <span class="hljs-string">"authToken"</span>)
    }

    <span class="hljs-comment">// ✅ Secure - Using Keychain as OWASP recommends</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">saveTokenSecurely</span><span class="hljs-params">(<span class="hljs-number">_</span> token: String)</span></span> <span class="hljs-keyword">throws</span> {
        <span class="hljs-keyword">let</span> data = token.data(using: .utf8)!
        <span class="hljs-keyword">let</span> query: [<span class="hljs-type">String</span>: <span class="hljs-type">Any</span>] = [
            kSecClass <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>: kSecClassGenericPassword,
            kSecAttrAccount <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>: <span class="hljs-string">"authToken"</span>,
            kSecValueData <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>: data,
            kSecAttrAccessible <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
        ]

        <span class="hljs-type">SecItemDelete</span>(query <span class="hljs-keyword">as</span> <span class="hljs-type">CFDictionary</span>)
        <span class="hljs-keyword">let</span> status = <span class="hljs-type">SecItemAdd</span>(query <span class="hljs-keyword">as</span> <span class="hljs-type">CFDictionary</span>, <span class="hljs-literal">nil</span>)

        <span class="hljs-keyword">guard</span> status == errSecSuccess <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">throw</span> <span class="hljs-type">StorageError</span>.saveFailed
        }
    }
}
</code></pre>
<p><strong>OWASP MSTG Checklist for Self-Audit:</strong></p>
<ul>
<li><p>[ ] Are all sensitive data encrypted at rest?</p>
</li>
<li><p>[ ] Is HTTPS enforced for all network calls?</p>
</li>
<li><p>[ ] Are certificates properly validated?</p>
</li>
<li><p>[ ] Is sensitive data excluded from logs?</p>
</li>
<li><p>[ ] Are API keys and secrets not hardcoded?</p>
</li>
<li><p>[ ] Is user input validated and sanitized?</p>
</li>
<li><p>[ ] Are authentication tokens stored securely in Keychain?</p>
</li>
</ul>
<p><strong>4. Automated Dependency Scanning</strong></p>
<p>Monitor your dependencies continuously for newly discovered vulnerabilities:</p>
<pre><code class="lang-swift"># <span class="hljs-type">For</span> <span class="hljs-type">CocoaPods</span> projects
gem install cocoapods-audit
pod audit

# <span class="hljs-type">For</span> <span class="hljs-type">Swift</span> <span class="hljs-type">Package</span> <span class="hljs-type">Manager</span>
# <span class="hljs-type">Use</span> <span class="hljs-type">GitHub</span> <span class="hljs-type">Dependabot</span> (free <span class="hljs-keyword">for</span> <span class="hljs-keyword">public</span> repos) or
brew install swift-outdated
swift-outdated
</code></pre>
<p>And set up automated alerts with these tools:</p>
<ul>
<li><p><strong>GitHub Dependabot:</strong> Automatically creates PRs when vulnerable dependencies are detected (free)</p>
</li>
<li><p><strong>Snyk</strong>: Free tier available for open-source projects</p>
</li>
<li><p><strong>OWASP Dependency-Check:</strong> Free command-line tool</p>
</li>
</ul>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Developing secure iOS apps using Swift is all about forward-thinking. You should do all you can to avoid these common errors, like insecure storage of data, poor network communication, hard-coded secrets, or poor authentication.</p>
<p>Using Keychain for confidential information, requiring HTTPS, input validation, and multifactor authentication are all steps that decrease risk.</p>
<p>Regular testing for security vulnerabilities and limiting third-party library use can also further enhance your app's security.</p>
<p>Security is a continuous responsibility. Swift provides tools, but the developers need to apply those tools carefully. Security being tackled right from the start protects users' information, creates trust, and protects the reputation of the application.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use UISearchController in iOS Apps ]]>
                </title>
                <description>
                    <![CDATA[ By Sai Balaji K Hello everyone! In this article we are going to learn how to use UISearchController in iOS Apps. What are we going to build? We are going to build a movie search application which uses the TMDB API to fetch movie info and display it u... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-to-use-uisearchcontroller-in-ios-apps/</link>
                <guid isPermaLink="false">66d460c7b3016bf139028d85</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Xcode ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 24 Mar 2022 15:55:58 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-21-at-8.11.31-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sai Balaji K</p>
<p>Hello everyone! In this article we are going to learn how to use UISearchController in iOS Apps.</p>
<h2 id="heading-what-are-we-going-to-build">What are we going to build?</h2>
<p>We are going to build a movie search application which uses the <a target="_blank" href="https://www.themoviedb.org/">TMDB</a> API to fetch movie info and display it using a UICollectionView based on a user's search query.</p>
<h2 id="heading-project-setup">Project Setup</h2>
<p>Open up Xcode and create a new blank iOS App project – make sure you select UIKit and not SwiftUI.</p>
<p>In this app we are going to use the MVC Pattern so organise the project by creating the following groups and Swift files:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-21-at-8.16.02-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now close your Xcode project. Open up the terminal and move to your project directory. Here we need to add <a target="_blank" href="https://cocoapods.org/pods/SDWebImage">SD WebImage</a> Cocoa Pods to asynchronously download and cache the movie poster images.</p>
<p>Type the following command in the terminal:</p>
<pre><code>pod init
</code></pre><p>Now when you list the contents of the directory, you can see that there is a new Podfile. Open the file using any text editor (here I've used Vim). Edit your Podfile so that it looks similar to the below image. Save and close the Podfile.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-21-at-8.20.28-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now that we have specified the SD WebImage, we can install the dependencies by running the below command:</p>
<pre><code>pod install
</code></pre><p>As you can see, we have successfully added the SD WebImage pod in our iOS project. Now run the below command to open our project in Xcode.</p>
<pre><code>open PROJECT_NAME.xcworkspace
</code></pre><p>After opening Xcode, make sure you build your project by hitting Command+B.</p>
<h2 id="heading-how-to-design-the-user-interface-using-uikit-and-programmatic-ui"><strong>How to Design the User Interface using UIKit and Programmatic UI</strong></h2>
<p>Our app needs three UIElements navigation bars to hold the search bar, UISearchBarController for actual search, and a UICollectionView to display the search results.</p>
<p>Open up your Scenedelegate.swift file and add the following code inside it which will connect to the session method:</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">scene</span><span class="hljs-params">(<span class="hljs-number">_</span> scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)</span></span> {
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> scene = (scene <span class="hljs-keyword">as</span>? <span class="hljs-type">UIWindowScene</span>) <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }
        window = <span class="hljs-type">UIWindow</span>(windowScene: scene)       window?.rootViewController=<span class="hljs-type">UINavigationController</span>(rootViewController:<span class="hljs-type">HomeVC</span>())
        window?.makeKeyAndVisible()
    }
</code></pre>
<p>Since we are using a programatic UI, first we need to mention our Root View controller – that is, the first screen which will be displayed when the user launches the app. </p>
<p>Here in this app we're using only one View Controller, so we wrap it inside a UINavigationController. This provides a navigation bar where we can place our UISearchController.</p>
<p>Open up the HomeVC.swift file and add the following properties:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> <span class="hljs-type">SearchBar</span>: <span class="hljs-type">UISearchController</span> = {
        <span class="hljs-keyword">let</span> sb = <span class="hljs-type">UISearchController</span>()
        sb.searchBar.placeholder = <span class="hljs-string">"Enter the movie name"</span>
        sb.searchBar.searchBarStyle = .minimal
        <span class="hljs-keyword">return</span> sb
    }()

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> <span class="hljs-type">MovieCollectionView</span>: <span class="hljs-type">UICollectionView</span> = {
        <span class="hljs-keyword">let</span> layout = <span class="hljs-type">UICollectionViewFlowLayout</span>()
        layout.scrollDirection = .vertical
        layout.itemSize = <span class="hljs-type">CGSize</span>(width: <span class="hljs-type">UIScreen</span>.main.bounds.width/<span class="hljs-number">3</span> - <span class="hljs-number">10</span>, height: <span class="hljs-number">200</span>)
        <span class="hljs-keyword">let</span> cv = <span class="hljs-type">UICollectionView</span>(frame: .zero, collectionViewLayout: layout)
        cv.register(<span class="hljs-type">MovieCell</span>.<span class="hljs-keyword">self</span>, forCellWithReuseIdentifier: <span class="hljs-type">MovieCell</span>.<span class="hljs-type">ID</span>)
        <span class="hljs-keyword">return</span> cv
    }()
</code></pre>
<p>First we create our UISearchController and configure its properties such as placeholder text and style. </p>
<p>Then we create a UICollectionView and specify the type of layout our collection view should use. In this case it is UICollectionViewFlowLayout and other properties such as scroll direction, item size, and specifying a custom CollectionView cell class which we will create later in our project.</p>
<p>Inside the HomeVC class create a new function and add the following code to configure auto-layout constraints programmatically for our UICollectionView:</p>
<pre><code class="lang-swift">    <span class="hljs-comment">//MARK: - HELPERS</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">configureUI</span><span class="hljs-params">()</span></span>{
        <span class="hljs-type">MovieCollectionView</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
        <span class="hljs-type">MovieCollectionView</span>.topAnchor.constraint(equalTo: view.topAnchor).isActive = <span class="hljs-literal">true</span>
        <span class="hljs-type">MovieCollectionView</span>.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = <span class="hljs-literal">true</span>
        <span class="hljs-type">MovieCollectionView</span>.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = <span class="hljs-literal">true</span>
        <span class="hljs-type">MovieCollectionView</span>.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = <span class="hljs-literal">true</span>
    }
</code></pre>
<p>First we say that we don't need to convert the auto resizing mask into the constraints. Then we pin our collection view to all four sides of our View Controller.</p>
<p>Inside the <code>viewDidLoad()</code> method add the following lines of code:</p>
<pre><code class="lang-swift">  <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewDidLoad</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.viewDidLoad()

        navigationItem.title  = <span class="hljs-string">"Movie Search"</span>
        view.backgroundColor = .systemBackground
        <span class="hljs-type">SearchBar</span>.searchResultsUpdater = <span class="hljs-keyword">self</span>
        navigationItem.searchController = <span class="hljs-type">SearchBar</span>
        view.addSubview(<span class="hljs-type">MovieCollectionView</span>)
        <span class="hljs-type">MovieCollectionView</span>.delegate = <span class="hljs-keyword">self</span>
        <span class="hljs-type">MovieCollectionView</span>.dataSource = <span class="hljs-keyword">self</span>
        configureUI()
    }
</code></pre>
<p>Here we first specify the title for our ViewController followed by the background color which is the systemBackground color. If the device is in light mode it shows a white background. If it is in dark mode, then it shows a dark background. </p>
<p>Then we set current the view controller as the search result updater, then add our SearchController to the navigation bar, add the UICollectionView to the ViewController, and setup delegate and datasource. Finally we pin the UICollectionView by using auto-layout.</p>
<p>Create an extension for HomeVC and implement the UISearchResultsUpdating protocol and its stub method updateSearchResults.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">HomeVC</span>: <span class="hljs-title">UISearchResultsUpdating</span></span>{

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateSearchResults</span><span class="hljs-params">(<span class="hljs-keyword">for</span> searchController: UISearchController)</span></span> {
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> query = searchController.searchBar.text <span class="hljs-keyword">else</span>{<span class="hljs-keyword">return</span>}

        }

    }


}
</code></pre>
<p>The <code>updateSearchResults()</code> method will be called whenever the text entered in the search bar changes or when the user taps the search button on their keyboard.</p>
<p>Next we need to create that custom UICollectionView cell. Inside the MovieCell.swift file, add the following code:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Foundation
<span class="hljs-keyword">import</span> UIKit
<span class="hljs-keyword">import</span> SDWebImage

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MovieCell</span>: <span class="hljs-title">UICollectionViewCell</span></span>{

    <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> <span class="hljs-type">ID</span> = <span class="hljs-string">"MovieCell"</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> <span class="hljs-type">MoviePosterImageView</span>: <span class="hljs-type">UIImageView</span> = {
        <span class="hljs-keyword">let</span> imageView = <span class="hljs-type">UIImageView</span>()
        imageView.contentMode = .scaleAspectFit
      <span class="hljs-comment">//  imageView.image = UIImage(systemName: "house")</span>
        <span class="hljs-keyword">return</span> imageView
    }()

    <span class="hljs-keyword">override</span> <span class="hljs-keyword">init</span>(frame: <span class="hljs-type">CGRect</span>) {
        <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>(frame: frame)
        addSubview(<span class="hljs-type">MoviePosterImageView</span>)
        configureUI()
    }

    <span class="hljs-keyword">required</span> <span class="hljs-keyword">init</span>?(coder: <span class="hljs-type">NSCoder</span>) {
        <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"init(coder:) has not been implemented"</span>)
    }

}

<span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">MovieCell</span></span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">configureUI</span><span class="hljs-params">()</span></span>{
        <span class="hljs-type">MoviePosterImageView</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
        <span class="hljs-type">MoviePosterImageView</span>.topAnchor.constraint(equalTo: topAnchor).isActive = <span class="hljs-literal">true</span>
        <span class="hljs-type">MoviePosterImageView</span>.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = <span class="hljs-literal">true</span>
        <span class="hljs-type">MoviePosterImageView</span>.leftAnchor.constraint(equalTo: leftAnchor).isActive = <span class="hljs-literal">true</span>
        <span class="hljs-type">MoviePosterImageView</span>.rightAnchor.constraint(equalTo: rightAnchor).isActive = <span class="hljs-literal">true</span>
    }
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateCell</span><span class="hljs-params">(posterURL: String?)</span></span>{
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> posterURL = posterURL {
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> <span class="hljs-type">CompleteURL</span> = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"https://image.tmdb.org/t/p/w500/\(posterURL)"</span>) <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-keyword">self</span>.<span class="hljs-type">MoviePosterImageView</span>.sd_setImage(with: <span class="hljs-type">CompleteURL</span>)
        }

    }
}
</code></pre>
<p>Here we create our custom collection view cell by sub-classing the UICollectionView class and implementing the <code>init()</code> functions. </p>
<p>We create a UIImageView to display the movie poster image and setup auto-layout constraints for it. Then we create a user defined function which takes the Movie poster URL string a parameter and downloads it asynchronously without affecting the UI Thread/Main thread. It does this by using the SD WebImage CocoaPod which we added earlier.</p>
<h2 id="heading-how-to-set-up-our-api">How to Set Up Our API</h2>
<p>Before moving on, you'll need to get your API key for the <a target="_blank" href="https://www.themoviedb.org/">TMDB</a> API by creating an account (it's free). We are going to use the Movie Search end point of the API which takes the API Key and movie name as parameters.</p>
<pre><code class="lang-url">https://api.themoviedb.org/3/search/movie?api_key=API_KEY_HERE&amp;query=batman
</code></pre>
<p>You can examine the API response by running it in Postman.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/Screenshot-2022-03-22-at-8.52.57-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-create-a-model-for-the-api-response">How to Create a Model for the API Response</h2>
<p>Now we get a JSON response from the API. We need to decode them to Swift which we can do by creating a model struct that implements the Codable protocol.</p>
<p>WE can generate the model struct for our JSON response easily by using JSON to Swift websites. Here is the model code for the API response – you can just copy and paste it inside the Model.swift file:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Foundation

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">TrendingTitleResponse</span>: <span class="hljs-title">Codable</span> </span>{
    <span class="hljs-keyword">let</span> results: [<span class="hljs-type">Title</span>]
}

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Title</span>: <span class="hljs-title">Codable</span> </span>{
    <span class="hljs-keyword">let</span> id: <span class="hljs-type">Int</span>
    <span class="hljs-keyword">let</span> media_type: <span class="hljs-type">String?</span>
    <span class="hljs-keyword">let</span> original_name: <span class="hljs-type">String?</span>
    <span class="hljs-keyword">let</span> original_title: <span class="hljs-type">String?</span>
    <span class="hljs-keyword">let</span> poster_path: <span class="hljs-type">String?</span>
    <span class="hljs-keyword">let</span> overview: <span class="hljs-type">String?</span>
    <span class="hljs-keyword">let</span> vote_count: <span class="hljs-type">Int</span>
    <span class="hljs-keyword">let</span> release_date: <span class="hljs-type">String?</span>
    <span class="hljs-keyword">let</span> vote_average: <span class="hljs-type">Double</span>
}

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">YoutubeSearchResponse</span>: <span class="hljs-title">Codable</span> </span>{
    <span class="hljs-keyword">let</span> items: [<span class="hljs-type">VideoElement</span>]
}


<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">VideoElement</span>: <span class="hljs-title">Codable</span> </span>{
    <span class="hljs-keyword">let</span> id: <span class="hljs-type">IdVideoElement</span>
}


<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">IdVideoElement</span>: <span class="hljs-title">Codable</span> </span>{
    <span class="hljs-keyword">let</span> kind: <span class="hljs-type">String</span>
    <span class="hljs-keyword">let</span> videoId: <span class="hljs-type">String</span>
}
</code></pre>
<h2 id="heading-how-to-perform-http-requests-using-swift">How to Perform  HTTP Requests Using Swift</h2>
<p>Now we need to write some Swift code to perform HTTP GET requests which return the JSON response of the API. </p>
<p>Swift provides a URLSession class which makes it easier to write networking code without needing any third party libraries like AFNetworking, AlamoFire, and so on.</p>
<p>Open APIService.swift and add the following code:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Foundation

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">APIService</span></span>{
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> shared = <span class="hljs-type">APIService</span>()
    <span class="hljs-keyword">let</span> session = <span class="hljs-type">URLSession</span>(configuration: .<span class="hljs-keyword">default</span>)

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getMovies</span><span class="hljs-params">(<span class="hljs-keyword">for</span> Query: String,completion:@escaping<span class="hljs-params">([Title]?,Error?)</span></span></span>-&gt;<span class="hljs-type">Void</span>){
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> <span class="hljs-type">FormatedQuery</span> = <span class="hljs-type">Query</span>.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)  <span class="hljs-keyword">else</span>{<span class="hljs-keyword">return</span>}

        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span>  <span class="hljs-type">SEARCH_URL</span> = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"https://api.themoviedb.org/3/search/movie?api_key=API_KEY_HERE&amp;query=\(FormatedQuery)"</span>) <span class="hljs-keyword">else</span> {<span class="hljs-built_in">print</span>(<span class="hljs-string">"INVALID"</span>)
            <span class="hljs-keyword">return</span>}



        <span class="hljs-keyword">let</span> task = session.dataTask(with: <span class="hljs-type">SEARCH_URL</span>) { data, response, error <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> error = error {
                <span class="hljs-built_in">print</span>(error.localizedDescription)
                completion(<span class="hljs-literal">nil</span>,error)
            }
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = data {
                <span class="hljs-keyword">do</span>{
                    <span class="hljs-keyword">let</span> decodedData = <span class="hljs-keyword">try</span> <span class="hljs-type">JSONDecoder</span>().decode(<span class="hljs-type">TrendingTitleResponse</span>.<span class="hljs-keyword">self</span>, from: data)
                 <span class="hljs-comment">//   print(decodedData)</span>
                    completion(decodedData.results,<span class="hljs-literal">nil</span>)
                }
                <span class="hljs-keyword">catch</span>{
                    <span class="hljs-built_in">print</span>(error)
                }
            }
        }
        task.resume()
    }
}
</code></pre>
<p>Here we created a class named API Service with the singleton pattern so we need an instance for this class as a static member of the class. Then we created a session for our networking task with the default configuration, followed by a user defined method getMovies(). </p>
<p>Then we created our networking task – in this case we need to perform HTTP GET requests which can be performed using the <code>dataTask()</code> method of the URLSession class. It takes the URL as a parameter and gives a completion handler which contains data returned from the API, error data if any error has occurred, and a response which has HTTP Response information such as status codes and their corresponding messages. </p>
<p>If there is any error, then we escape out of this function with error data. If not, then we decode our JSON data based on our Swift Model and escape out of this function with the decoded data.</p>
<h2 id="heading-how-to-display-the-search-results-on-the-uicollectionview">How to Display the Search Results on the UICollectionView</h2>
<p>In HomeVC.swift, create a private property which is an array of Title objects. These will hold each movie's info returned by the API.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> <span class="hljs-type">Movies</span> = [<span class="hljs-type">Title</span>]()
</code></pre>
<p>In HomeVC.swift create an extension for the HomeVC class and implement the UIColletionViewDelegate and UICollectionViewDatasource protocols. Then implement numberOfItemsInSection (which is equal to the number of movies returned by the API) and cellForItemAt (which actually populates the cell with API responses, like download and set the poster image).</p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-type">Movies</span>.<span class="hljs-built_in">count</span>
    }
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: <span class="hljs-type">MovieCell</span>.<span class="hljs-type">ID</span>, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>? <span class="hljs-type">MovieCell</span>{
           <span class="hljs-comment">// cell.backgroundColor = .systemBackground</span>

            cell.updateCell(posterURL: <span class="hljs-type">Movies</span>[indexPath.row].poster_path)
            <span class="hljs-keyword">return</span> cell
        }
        <span class="hljs-keyword">return</span> <span class="hljs-type">UICollectionViewCell</span>()

    }
</code></pre>
<p>Finally we need to make actual API call which we do inside the <code>updateSearchResults()</code> delegate method which we have implemented previously. Inside that method add the following code:</p>
<pre><code class="lang-swift">    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateSearchResults</span><span class="hljs-params">(<span class="hljs-keyword">for</span> searchController: UISearchController)</span></span> {
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> query = searchController.searchBar.text <span class="hljs-keyword">else</span>{<span class="hljs-keyword">return</span>}
        <span class="hljs-type">APIService</span>.shared.getMovies(<span class="hljs-keyword">for</span>:query.trimmingCharacters(<span class="hljs-keyword">in</span>: .whitespaces)) { titles, error <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> titles = titles {
                <span class="hljs-keyword">self</span>.<span class="hljs-type">Movies</span> = titles
                <span class="hljs-type">DispatchQueue</span>.main.async {
                    <span class="hljs-keyword">self</span>.<span class="hljs-type">MovieCollectionView</span>.reloadData()
                }

            }
        }

    }
</code></pre>
<p>Here, whenever the user types in the search bar or presses the search button, we make an HTTP GET request to fetch a movie (based on the name entered in the search bar). Then we reload the CollectionView which updates the collection view cells with the movie poster. </p>
<p>Note that we need to do this in the Main Thread/UI Thread, because by default iOS automatically makes HTTP request in background thread. This means that we need to use UI/Main Thread to update our UI elements. </p>
<p>Now run your app in the simulator to see the result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/ezgif.com-gif-maker--3-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Congratulations! You have learned to use UISearchController in iOS apps.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add the Realm Database to an iOS CRUD App using Swift ]]>
                </title>
                <description>
                    <![CDATA[ By Sai Balaji K Hello, everyone! In this article we are going to learn how to add the Realm database to an iOS app.  We'll create a simple ToDo app so you can learn how to perform CRUD (Create, Read, Update, Delete) operations in the Realm database. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/add-realm-database-to-ios-crud-app-with-with-swift/</link>
                <guid isPermaLink="false">66d460c5230dff0166905863</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 27 Apr 2021 18:21:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/605aa5a8687d62084bf6b611.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sai Balaji K</p>
<p>Hello, everyone! In this article we are going to learn how to add the Realm database to an iOS app. </p>
<p>We'll create a simple ToDo app so you can learn how to perform CRUD (Create, Read, Update, Delete) operations in the Realm database.</p>
<h2 id="heading-what-is-realm">What is Realm?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-24-at-8.09.31-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Realm is an open-source mobile database which is developer friendly and easy to use. You can also use it as an alternative to Core Data in iOS apps. </p>
<p>Realm is a cross platform mobile database, which means that you can use it in native Android and iOS apps and also in cross platform apps like those created using React Native. It supports Objective-C, Swift, Java, Kotlin, C#, and JavaScript.</p>
<h2 id="heading-how-to-set-up-realm-in-your-ios-project">How to Set Up Realm in Your iOS Project</h2>
<p>We can add Realm to our iOS project using SPM (the Swift Package Manager), Cocoa Pods, or Carthage. Here, we are going to use Cocoa Pods to add Realm Pod to our iOS project.</p>
<ol>
<li>Open up Xcode and create a blank iOS app project with UIKit and Swift without using Core Data.</li>
<li>Now close Xcode and open up the terminal. Navigate to your project directory using the terminal.</li>
<li>Run the following command to create a PodFile.</li>
</ol>
<pre><code class="lang-command">pod init
</code></pre>
<ol start="4">
<li>Now when you list the contents of the directory you can see that there is a new Podfile. Open the file using any text editor (here I've used Vim). Edit your Podfile so that it looks similar to the below image. Save and close the Podfile.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-24-at-8.23.07-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now that we have specified the dependence for Realm DB, we can install the dependencies by running the below command:</p>
<pre><code class="lang-command">pod install
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-24-at-8.26.21-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, we have successfully added the Realm DB dependency in our iOS project. Now run the below command to open our project in Xcode.</p>
<pre><code class="lang-command">open YOUR_APP_NAME.xcworkspace
</code></pre>
<p>Note: after opening Xcode, make sure you build your project by pressing Command+B.</p>
<h2 id="heading-how-to-design-your-user-interface-in-realm">How to Design Your User Interface in Realm</h2>
<p>We are going to keep our app's UI simple. Open up Main.storyboard and create a simple UI as shown below by adding a table view with a prototype cell. Then embed a navigation controller and create the IBOutlets for the tableview in the ViewController.swift file:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-24-at-8.32.42-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-create-a-data-model-in-realm">How to Create a Data Model in Realm</h2>
<p>In our ToDo app, each task has a task name and a task id. We are going to create a Model class to represent the todo task. In the project navigator right click and create a new Swift file, and add the below code.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Foundation
<span class="hljs-keyword">import</span> RealmSwift


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToDoTask</span>:<span class="hljs-title">Object</span>
</span>{
    <span class="hljs-meta">@objc</span> <span class="hljs-keyword">dynamic</span> <span class="hljs-keyword">var</span> tasknote: <span class="hljs-type">String?</span>
    <span class="hljs-meta">@objc</span> <span class="hljs-keyword">dynamic</span> <span class="hljs-keyword">var</span> taskid: <span class="hljs-type">String?</span>
}
</code></pre>
<p>Her we created our model class named ToDoTask. It inherits the Object class which is a class that comes with RealmDB. This class handles all the under the hood processes of saving the data created using this model class in the database.</p>
<p>We also added two properties: <code>tasknote</code>, which is the task to be done, and <code>taskid</code> – both of type string. <code>@objc</code> means that your Swift code is visible to Objective C and <code>dynamic</code> means you want to use Objective C dynamic dispatch.</p>
<h2 id="heading-basic-crud-app-functions">Basic CRUD App functions</h2>
<p>Our app will perform the following functions:</p>
<ol>
<li>Get input from the user using AlertViewController.</li>
<li>Add the input to the database and also to the table view.</li>
<li>Allow the user to edit their input.</li>
<li>Swipe to delete a row to remove the data from both the table view and the database.</li>
<li>Fetch all the data (if present) from the database and display it in the table view.</li>
</ol>
<h3 id="heading-how-to-get-input-from-the-user-using-alertviewcontroller">How to get input from the user using AlertViewController</h3>
<p>Open up <code>ViewController.swift</code> and add the below code inside the <code>ViewDidLoad()</code> method. And create a new function called <code>addTask()</code> and add the code to display the alert view controller with a text box to get input from the user. </p>
<p>Now when the right bar button is pressed it will call the <code>addTask()</code> function which will display the <code>alertviewcontroller</code> with a text field to get user input.</p>
<pre><code class="lang-swift">navigationItem.rightBarButtonItem = <span class="hljs-type">UIBarButtonItem</span>(image: .add, style: .done, target: <span class="hljs-keyword">self</span>, action: #selector(addTask))

navigationController?.navigationBar.prefersLargeTitles = <span class="hljs-literal">true</span>

title = <span class="hljs-string">"RealmDB"</span>
</code></pre>
<pre><code class="lang-swift"><span class="hljs-meta">@objc</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">addTask</span><span class="hljs-params">()</span></span>
    { 
        <span class="hljs-keyword">let</span> ac = <span class="hljs-type">UIAlertController</span>(title: <span class="hljs-string">"Add Note"</span>, message: <span class="hljs-literal">nil</span>, preferredStyle: .alert)

        ac.addTextField(configurationHandler: .<span class="hljs-keyword">none</span>)

        ac.addAction(<span class="hljs-type">UIAlertAction</span>(title: <span class="hljs-string">"Add"</span>, style: .<span class="hljs-keyword">default</span>, handler: { (<span class="hljs-type">UIAlertAction</span>) <span class="hljs-keyword">in</span>

              <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> text = ac.textFields?.first?.text
            {
                <span class="hljs-built_in">print</span>(text)
            }

        }))
        ac.addAction(<span class="hljs-type">UIAlertAction</span>(title: <span class="hljs-string">"Cancel"</span>, style: .cancel, handler: <span class="hljs-literal">nil</span>))
        present(ac, animated: <span class="hljs-literal">true</span>, completion: <span class="hljs-literal">nil</span>)
    }
</code></pre>
<h3 id="heading-how-to-add-the-input-to-the-database-and-table-view">How to add the input to the database and table view</h3>
<p>To save data into Realm, first we need obtain an instance for Realm through which we can access all the methods needed for CRUD operations. Create a property of type Realm in the <code>ViewController.swift</code> file and initialise it in the <code>viewDidLoad()</code> method.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> realmDB: <span class="hljs-type">Realm!</span>
</code></pre>
<pre><code class="lang-swift"> <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewDidLoad</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.viewDidLoad()

        navigationItem.rightBarButtonItem = <span class="hljs-type">UIBarButtonItem</span>(image: .add, style: .done, target: <span class="hljs-keyword">self</span>, action: #selector(addTask))
        navigationController?.navigationBar.prefersLargeTitles = <span class="hljs-literal">true</span>
        title = <span class="hljs-string">"RealmDB"</span>

        realmDB = <span class="hljs-keyword">try</span>! <span class="hljs-type">Realm</span>()

    }
</code></pre>
<p>Create an empty array of type our DataModel (ToDoTask). This array will hold all the tasks which need to be added to the table view and database. </p>
<p>Now inside the <code>addTask()</code> function modify the Add action closure so that it gets the user input and creates a random ID for that input. Then append it to our array and save it to the database.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">var</span> tasks = [<span class="hljs-type">ToDoTask</span>]()
</code></pre>
<pre><code class="lang-swift"> <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> text = ac.textFields?.first?.text
            {
                <span class="hljs-comment">//Add data to data model array</span>
                <span class="hljs-keyword">let</span> t = <span class="hljs-type">ToDoTask</span>()
                t.taskid = <span class="hljs-type">UUID</span>().uuidString
                t.tasknote = text
                <span class="hljs-keyword">self</span>.tasks.append(t)

                <span class="hljs-comment">//Add data to database</span>
                <span class="hljs-keyword">try</span>! <span class="hljs-keyword">self</span>.realmDB.write {
                    <span class="hljs-keyword">self</span>.realmDB.add(t)
                }
                <span class="hljs-comment">//Update table view UI</span>
                <span class="hljs-keyword">self</span>.tasktv.reloadData()
            }
</code></pre>
<p>Now when you run the app, the data will be saved in the database. But it will not show in table view because we have not implemented the delegate methods. </p>
<p>Make the ViewController class implement the <code>UITableViewDelegate</code> and <code>UITableViewDataSource</code> protocols and add the protocol stubs. </p>
<p>Now inside the <code>numberOfRowsInSection</code> method, return the count of our tasks array which gives the number of rows to be added to the table view. This is equal to the number of elements in tasks array.</p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, numberOfRowsInSection section: 
 Int)</span></span> -&gt; <span class="hljs-type">Int</span> 
 {
        <span class="hljs-keyword">return</span> tasks.<span class="hljs-built_in">count</span>;
 }
</code></pre>
<p>The next thing we need to do is specify the content in each row. We can do this using the <code>cellForRowAt</code> delegate method. Here we dequeue a cell using the identifier which we have mentioned in storyboard and specify the label text as the tasks array element tasknote property.</p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, cellForRowAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UITableViewCell</span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> cell = tableView.dequeueReusableCell(withIdentifier: <span class="hljs-string">"cell"</span>)
        {
            cell.textLabel?.text = tasks[indexPath.row].tasknote
            <span class="hljs-keyword">return</span> cell
        }
        <span class="hljs-keyword">return</span> <span class="hljs-type">UITableViewCell</span>()
    }
</code></pre>
<h3 id="heading-how-to-allow-users-to-edit-their-input">How to allow users to edit their input</h3>
<p>Now we have to allow the user to edit their entered tasks and update the changes in both the database and UI. We can do this using similar methods of getting input from the user. Implement the <code>didSelectRowAt</code> delegate method which will be called when user taps the table view row. </p>
<p>Add the below code which displays an <code>AlertViewController</code> with a text view. Then update the content of the cell with the entered text, and at the same time update the database contents.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, didSelectRowAt indexPath: IndexPath)</span></span> {

        <span class="hljs-keyword">let</span> tasktomodify = tasks[indexPath.row]
        <span class="hljs-keyword">let</span> ac = <span class="hljs-type">UIAlertController</span>(title: <span class="hljs-string">"Update task"</span>, message: <span class="hljs-literal">nil</span>, preferredStyle: .alert)

        ac.addTextField(configurationHandler: .<span class="hljs-keyword">none</span>)
        ac.addAction(<span class="hljs-type">UIAlertAction</span>(title: <span class="hljs-string">"Ok"</span>, style: .<span class="hljs-keyword">default</span>, handler: { (<span class="hljs-type">UIAlertAction</span>) <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> text = ac.textFields?.first?.text
            {
                <span class="hljs-keyword">if</span>(!text.isEmpty)
                {
                <span class="hljs-keyword">try</span>! <span class="hljs-keyword">self</span>.realmDB.write({
                    tasktomodify.tasknote = text
                })
                <span class="hljs-keyword">self</span>.tasktv.reloadData()
                }
            }
        }))

        present(ac, animated: <span class="hljs-literal">true</span>, completion: <span class="hljs-literal">nil</span>)
    }
</code></pre>
<h3 id="heading-how-to-swipe-to-delete-a-row-amp-remove-the-data-from-both-the-table-view-and-database">How to swipe to delete a row &amp; remove the data from both the table view and database</h3>
<p>Here we are going to implement a swipe to delete feature in our table view so that users can delete their tasks. But under the hood when the user swipe deletes a table view row then it should delete the data from database, data model array, and update the UI of the table view. </p>
<p>We can do this by implementing the <strong>commit editingStyle</strong> delegate method and adding the following code:</p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)</span></span> {
        <span class="hljs-keyword">if</span> editingStyle == .delete
        {
            <span class="hljs-keyword">let</span> tasktoDelete = tasks[indexPath.row]
            <span class="hljs-keyword">try</span>! realmDB.write({
                realmDB.delete(tasktoDelete)
                <span class="hljs-keyword">self</span>.tasks.remove(at: indexPath.row)
                <span class="hljs-keyword">self</span>.tasktv.deleteRows(at: [indexPath], with: .fade)
            })
        }
    }
</code></pre>
<h3 id="heading-how-to-fetch-all-the-data-if-present-from-the-database-and-display-it-in-the-table-view">How to fetch all the data (if present) from the database and display it in the table view</h3>
<p>Now we are going to implement our last operation, Read. Whenever the user launches the app, it should fetch data from the database (if data is present) and display it in the table view. </p>
<p>We can do this by creating a function <code>getTodo</code> in the view controller swift file and adding the following code inside it:</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getTodos</span><span class="hljs-params">()</span></span>
    {
       <span class="hljs-comment">//Get all the data from the database</span>
        <span class="hljs-keyword">let</span> notes = realmDB.objects(<span class="hljs-type">ToDoTask</span>.<span class="hljs-keyword">self</span>)

        <span class="hljs-comment">//Clear the model data array to prevent duplicates</span>
        <span class="hljs-keyword">self</span>.tasks.removeAll()

        <span class="hljs-comment">/*If the fetched data is not empty then add it to model data array and update the UI */</span>
        <span class="hljs-keyword">if</span>(!notes.isEmpty)
        {
        <span class="hljs-keyword">for</span> n <span class="hljs-keyword">in</span> notes
        {

            <span class="hljs-keyword">self</span>.tasks.append(n)

        }
            <span class="hljs-keyword">self</span>.tasktv.reloadData()
        }


    }
</code></pre>
<h2 id="heading-bonus-tip-how-to-view-your-database-content-in-an-ios-simulator">Bonus Tip: How to View Your Database Content in an iOS Simulator</h2>
<p>Now when you run your app, you can see that it works as expected. But how can we check if the data is really stored in the database? We can use an app called MongoDB Realm Studio through which we can view our data stored in the Realm database of the simulator.</p>
<blockquote>
<p>Note that this method works only when you test the app using iOS simulator</p>
</blockquote>
<p>In the <code>viewDidLoad()</code> method, add the below line of code which will print the real file path of our app:</p>
<pre><code class="lang-swift"> <span class="hljs-built_in">print</span>(realmDB.configuration.fileURL!)
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-24-at-9.48.59-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now copy the file path printed in the console, open up the terminal, and run the following command:</p>
<pre><code class="lang-command">open REALM_FILE_PATH_HERE
</code></pre>
<blockquote>
<p>Make sure you have downloaded MongoDB Realm Studio from the browser before running the above command.</p>
</blockquote>
<p>Now it will open the RealmFile of the app in MongoDB Realm Studio. This will display the data stored in the database in a table format. </p>
<p>If you make changes to your data by editing or deleting the task, the changes will be reflected in the MongoDB Realm Studio app:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/Screenshot-2021-03-24-at-9.55.29-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Congratulations! You have made a simple app which implements CRUD operations in iOS apps.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Setup Instagram-like Video Stories in Your App ]]>
                </title>
                <description>
                    <![CDATA[ By Agam Mahajan The article will teach you how you can show multiple videos in one view, like we see in Instagram Stories. We'll also learn how to cache the videos in the user's device to help save that user's data and network calls and smooth out th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/video-stories-and-caching-ios/</link>
                <guid isPermaLink="false">66d45d5cbd438296f45cd377</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ caching ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ video ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 22 Sep 2020 22:01:31 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/1_gYkQNP0BaohLJ8hDKL1C6w-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Agam Mahajan</p>
<p>The article will teach you how you can show multiple videos in one view, like we see in Instagram Stories.</p>
<p>We'll also learn how to cache the videos in the user's device to help save that user's data and network calls and smooth out their experience.</p>
<p>A quick note: this implementation is for iOS, but the same logic can be applied in other codebases as well.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/ezgif.com-video-to-gif--5-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In general, whenever we want to play a video, we get the video URL and simply present <code>**AVPlayerViewController**</code> with that URL.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> videoURL = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"Sample-Video-Url"</span>)
<span class="hljs-keyword">let</span> player = <span class="hljs-type">AVPlayer</span>(url: videoURL!)
<span class="hljs-keyword">let</span> playerViewController = <span class="hljs-type">AVPlayerViewController</span>()
playerViewController.player = player
<span class="hljs-keyword">self</span>.present(playerViewController, animated: <span class="hljs-literal">true</span>) {
    playerViewController.player.play()
}
</code></pre>
<p>Pretty straightforward, right?</p>
<p>But the drawback of this implementation is that you <strong>can’t</strong> <strong>customiz</strong>e it. Which, if you are working for a good product company, will be an everyday ask. :D</p>
<p>Alternatively, we can use <code>**AVPlayerLayer**</code> which will do a similar job – but it allows us to customize the view and other elements.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> videoURL = <span class="hljs-type">URL</span>(string: <span class="hljs-string">"Sample-Video-Url"</span>)
<span class="hljs-keyword">let</span> player = <span class="hljs-type">AVPlayer</span>(url: videoURL!)
<span class="hljs-keyword">let</span> playerLayer = <span class="hljs-type">AVPlayerLayer</span>(player: player)
playerLayer.frame = <span class="hljs-keyword">self</span>.view.bounds
<span class="hljs-keyword">self</span>.view.layer.addSublayer(playerLayer)
player.play()
</code></pre>
<p>But what if you want to combine multiple videos, similar to <strong>Instagram stories</strong>? Then we probably have to dive in a bit deeper.</p>
<h2 id="heading-coming-back-to-the-problem-statement">Coming Back to the Problem Statement</h2>
<p>Now, let me tell you about my use case.</p>
<p>In my company, Swiggy, we want to be able to show multiple videos, where each video should be shown x number of times.</p>
<p>On top of that, it should have an Instagram-like stories feature.</p>
<ul>
<li>Video-2 should seamlessly autoplay after video-1, and so on</li>
<li>It should jump to corresponding videos whenever the user taps left or right.</li>
</ul>
<p>If you think caching could be the answer, don't worry – I’ll get to that in a bit.</p>
<h3 id="heading-multiple-layers-in-one-view">Multiple layers in one view</h3>
<p>First things first, we need to figure out how to add multiple videos in one view.</p>
<p>What we can do is create one <code>**AVPlayerLayer**</code> and assign the first video to it. When the first video is finished, then we assign the next video to the same <code>**AVPlayerLayer**</code> .</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">addPlayer</span><span class="hljs-params">(player: AVPlayer)</span></span> {
    player.currentItem?.seek(to: <span class="hljs-type">CMTime</span>.zero, completionHandler: <span class="hljs-literal">nil</span>)
    playerViewModel?.player = player
    playerView.playerLayer.player = player
}
</code></pre>
<p>To jump to the previous or next video, we can do the following:</p>
<ul>
<li>Add a tap gesture on the view</li>
<li>If the touch location ‘x’ is less than half of the screen, then assign the previous video, else assign the next video</li>
</ul>
<pre><code class="lang-swift"><span class="hljs-meta">@objc</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">didTapSnap</span><span class="hljs-params">(<span class="hljs-number">_</span> sender: UITapGestureRecognizer)</span></span> {
   <span class="hljs-keyword">let</span> touchLocation = sender.location(ofTouch: <span class="hljs-number">0</span>, <span class="hljs-keyword">in</span>: view)
   <span class="hljs-keyword">if</span> touchLocation.x &lt; view.frame.width/<span class="hljs-number">2</span> {
     changePlayer(forward: <span class="hljs-literal">false</span>)
     } 
   <span class="hljs-keyword">else</span> {
     fillupLastPlayedSnap()
     changePlayer(forward: <span class="hljs-literal">true</span>)
    }
}
</code></pre>
<p>There we go. We now have our own Insta-like Stories video feature.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/13ZwNq4FnbM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>But our task is not done yet!</p>
<h2 id="heading-now-back-to-caching">Now Back to Caching</h2>
<p>We don't want it to be the case that every time a user navigates from one video to another, it starts to download the video from the beginning.</p>
<p>Also, if the video is shown again in the next session, we don't need to do another server call. </p>
<p>If we can cache the video, then the user’s internet will be saved. The load on the server will also be reduced.</p>
<p>Finally, the UX will improve as the user won't have to wait a long time to load the video.</p>
<p><strong>As a good developer, reducing</strong> a <strong>user’s internet usage should be our priority.</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/less-data-usage-happy-customer.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Less data usage, happy customer</em></p>
<h3 id="heading-load-videos-asynchronously">Load Videos <strong>Asynchronously</strong></h3>
<p>The first thing we can use to load videos is <strong>loadValuesAsynchronously</strong>.</p>
<p>According to <a target="_blank" href="https://developer.apple.com/documentation/avfoundation/avasynchronouskeyvalueloading/1387321-loadvaluesasynchronously">the Apple documentation</a>, <strong>loadValuesAsynchronously:</strong></p>
<blockquote>
<p><em>Tells the asset to load the values of all of the specified keys (property names) that are not already loaded.</em></p>
</blockquote>
<p>The advantage here is that it saves the video until it is rendered. So it will not download the video from the start whenever the user navigates to a previous video. It will only download the part which was not rendered earlier.</p>
<p><strong>Let's look at an e</strong>xample<em>**</em>: say we have Video_1 that is 15 seconds long, and the user saw 10 seconds of that video before jumping to Video_2. </p>
<p>Now if the user comes back to Video_1 again by tapping to the left, <strong>loadValuesAsynchronously</strong> will have that 10 seconds of video saved and will only download the remaining (unwatched) 5 seconds.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">asynchronouslyLoadURLAssets</span><span class="hljs-params">(<span class="hljs-number">_</span> newAsset: AVURLAsset)</span></span> {
    <span class="hljs-type">DispatchQueue</span>.main.async {
            newAsset.loadValuesAsynchronously(forKeys: <span class="hljs-keyword">self</span>.assetKeysRequiredToPlay) {
                <span class="hljs-keyword">for</span> key <span class="hljs-keyword">in</span> <span class="hljs-keyword">self</span>.assetKeysRequiredToPlay {
                    <span class="hljs-keyword">var</span> error: <span class="hljs-type">NSError?</span>
                    <span class="hljs-keyword">if</span> newAsset.statusOfValue(forKey: key, error: &amp;error) == .failed {
                        <span class="hljs-keyword">self</span>.delegate?.playerDidFailToPlay(message: <span class="hljs-string">"Can't use this AVAsset because one of it's keys failed to load"</span>)
                        <span class="hljs-keyword">return</span>
                    }
                }

                <span class="hljs-keyword">if</span> !newAsset.isPlayable || newAsset.hasProtectedContent {
                    <span class="hljs-keyword">self</span>.delegate?.playerDidFailToPlay(message: <span class="hljs-string">"Can't use this AVAsset because it isn't playable or has protected content"</span>)
                    <span class="hljs-keyword">return</span>
                }
                <span class="hljs-keyword">let</span> currentItem = <span class="hljs-type">AVPlayerItem</span>(asset: newAsset)
                <span class="hljs-keyword">let</span> currentPlayer = <span class="hljs-type">AVPlayer</span>(playerItem: currentItem)
                <span class="hljs-keyword">self</span>.delegate?.playerDidSuccesToPlay(playerDetail: currentPlayer)
            }

        }
</code></pre>
<p>You can find more details on <strong>loadValuesAsynchronously</strong> at this <a target="_blank" href="https://developer.apple.com/documentation/avfoundation/avasynchronouskeyvalueloading/1387321-loadvaluesasynchronously">link</a>.</p>
<p>The caveat here is it persists video data for that session only. If the user closes and comes back to the app, the video has to be downloaded again.</p>
<p>So what other options do we have?</p>
<h3 id="heading-saving-videos-in-device">Saving Videos in Device</h3>
<p>Now comes <strong>Video Caching</strong>!</p>
<p>When the video is rendered completely, we can export the video and save it to the user’s device. When the video comes up again in their next session, we can pick the video from the device and simply load it.</p>
<p><strong>AVAssetExportSession</strong><br>According to <a target="_blank" href="https://developer.apple.com/documentation/avfoundation/avassetexportsession">Apple's documentation</a>:</p>
<blockquote>
<p><em>An object that transcodes the contents of an asset source object to create an output of the form described by a specified export preset.</em></p>
</blockquote>
<p>This means that AVAssetExportSession acts as an exporter, through which we can save the file to the user’s device. We have to give the output URL and the output file type.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> exporter = <span class="hljs-type">AVAssetExportSession</span>(asset: avUrlAsset, presetName: <span class="hljs-type">AVAssetExportPresetHighestQuality</span>)
exporter?.outputURL = outputURL
exporter?.outputFileType = <span class="hljs-type">AVFileType</span>.mp4

exporter?.exportAsynchronously(completionHandler: {
    <span class="hljs-built_in">print</span>(exporter?.status.rawValue)
    <span class="hljs-built_in">print</span>(exporter?.error)
})
</code></pre>
<p>You can find more details on <strong>AVAssetExportSession</strong> at this <a target="_blank" href="https://developer.apple.com/documentation/avfoundation/avassetexportsession">link</a>.</p>
<p>Now the only thing left is to fetch the data from the cache and load the video.</p>
<p>Before loading, check if the video is present in the cache. Then fetch that local URL and give it to <strong>loadValuesAsynchronously.</strong></p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> cacheUrl = <span class="hljs-type">FindCachedVideoURL</span>(forVideoId: videoId) {
    <span class="hljs-keyword">let</span> cacheAsset = <span class="hljs-type">AVURLAsset</span>(url: cacheUrl)
    asynchronouslyLoadURLAssets(cacheAsset)
}
<span class="hljs-keyword">else</span> {
  asynchronouslyLoadURLAssets(newAsset)
}
</code></pre>
<p>Caching will help reduce a lot of user data usage as well as server load (sometimes up to TBs of data).</p>
<h2 id="heading-other-use-cases-for-caching">Other use cases for caching</h2>
<p>What other use cases we can handle with caching? The following are examples of ways you could use caching here:</p>
<h3 id="heading-ensure-optimum-storage">Ensure Optimum Storage</h3>
<p>Before saving the video on the device, you should check whether enough storage is present on the device to do so.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isStorageAvailable</span><span class="hljs-params">()</span></span> -&gt; <span class="hljs-type">Bool</span> {
   <span class="hljs-keyword">let</span> fileURL = <span class="hljs-type">URL</span>(fileURLWithPath: <span class="hljs-type">NSHomeDirectory</span>() <span class="hljs-keyword">as</span> <span class="hljs-type">String</span>)
   <span class="hljs-keyword">do</span> {
      <span class="hljs-keyword">let</span> values = <span class="hljs-keyword">try</span> fileURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey, .volumeTotalCapacityKey])
      <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> totalSpace = values.volumeTotalCapacity,
      <span class="hljs-keyword">let</span> freeSpace = values.volumeAvailableCapacityForImportantUsage <span class="hljs-keyword">else</span> {
          <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
      }
      <span class="hljs-keyword">if</span> freeSpace &gt; minimumSpaceRequired {
         <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
      } <span class="hljs-keyword">else</span> {
          <span class="hljs-comment">// Capacity is unavailable</span>
          <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
      }  
    <span class="hljs-keyword">catch</span> {}
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>
}
</code></pre>
<h3 id="heading-remove-deprecated-videos">Remove Deprecated Videos</h3>
<p>You can have a timestamp for each video so that you can clean up old videos from device memory after a certain number of days.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">cleanExpiredVideos</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">let</span> currentTimeStamp = <span class="hljs-type">Date</span>().timeIntervalSince1970
        <span class="hljs-keyword">var</span> expiredKeys: [<span class="hljs-type">String</span>] = []
        <span class="hljs-keyword">for</span> videoData <span class="hljs-keyword">in</span> videosDict <span class="hljs-keyword">where</span> currentTimeStamp - videoData.value.timeStamp &gt;= expiryTime {
            <span class="hljs-comment">// video is expired. delete</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-number">_</span> = popupVideosDict[videoData.key] {
                expiredKeys.append(videoData.key)
            }
        }
        <span class="hljs-keyword">for</span> key <span class="hljs-keyword">in</span> expiredKeys {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> <span class="hljs-number">_</span> = popupVideosDict[key] {
                popupVideosDict.removeValue(forKey: key)
                deleteVideo(<span class="hljs-type">ForVideoId</span>: key)
            }
        }
    }
</code></pre>
<h3 id="heading-maintain-a-limited-number-of-videos">Maintain a limited number of videos</h3>
<p>You can make sure only a limited number of videos are saved in the file at a time. Let's say 10. </p>
<p>Then when the 11th video comes, you can have it delete the least-viewed video and replace it with the new one. This will also help you not consume too much of the user’s device memory.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">removeVideoIfMaxNumberOfVideosReached</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> popupVideosDict.<span class="hljs-built_in">count</span> &gt;= maxVideosAllowed {
            <span class="hljs-comment">// remove the least recently used video</span>
            <span class="hljs-keyword">let</span> sortedDict = popupVideosDict.keysSortedByValue { (v1, v2) -&gt; <span class="hljs-type">Bool</span> <span class="hljs-keyword">in</span>
                v1.timeStamp &lt; v2.timeStamp
            }
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> videoId = sortedDict.first <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span>
            }
            popupVideosDict.removeValue(forKey: videoId)
            deleteVideo(<span class="hljs-type">ForVideoId</span>: videoId)
        }
    }
</code></pre>
<h3 id="heading-measure-impact">Measure Impact</h3>
<p>Don’t forget to add logs, so that you can measure the impact of your feature. I have used a custom New Relic Log Event to do so:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">findCachedVideoURL</span><span class="hljs-params">(forVideoId id: String)</span></span> -&gt; <span class="hljs-type">URL?</span> {
        <span class="hljs-keyword">let</span> nsDocumentDirectory = <span class="hljs-type">FileManager</span>.<span class="hljs-type">SearchPathDirectory</span>.documentDirectory
        <span class="hljs-keyword">let</span> nsUserDomainMask = <span class="hljs-type">FileManager</span>.<span class="hljs-type">SearchPathDomainMask</span>.userDomainMask
        <span class="hljs-keyword">let</span> paths = <span class="hljs-type">NSSearchPathForDirectoriesInDomains</span>(nsDocumentDirectory, nsUserDomainMask, <span class="hljs-literal">true</span>)
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> dirPath = paths.first {
            <span class="hljs-keyword">let</span> fileURL = <span class="hljs-type">URL</span>(fileURLWithPath: dirPath).appendingPathComponent(folderPath).appendingPathComponent(id + <span class="hljs-string">".mp4"</span>)
            <span class="hljs-keyword">let</span> filePath = fileURL.path
            <span class="hljs-keyword">let</span> fileManager = <span class="hljs-type">FileManager</span>.<span class="hljs-keyword">default</span>
            <span class="hljs-keyword">if</span> fileManager.fileExists(atPath: filePath) {
                <span class="hljs-type">NewRelicService</span>.sendCustomEvent(with: <span class="hljs-type">NewRelicEventType</span>.statusCodes,
                                                                   eventName: <span class="hljs-type">NewRelicEventName</span>.videoCacheHit,
                                                                   attributes: [<span class="hljs-type">NewRelicAttributeKey</span>.videoSize: fileURL.fileSizeString])
                <span class="hljs-keyword">return</span> fileURL
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
            }
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }
</code></pre>
<p>To convert the file size to a readable format, I fetch the file size and convert it to Mbs.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">URL</span> </span>{
    <span class="hljs-keyword">var</span> attributes: [<span class="hljs-type">FileAttributeKey</span> : <span class="hljs-type">Any</span>]? {
        <span class="hljs-keyword">do</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">try</span> <span class="hljs-type">FileManager</span>.<span class="hljs-keyword">default</span>.attributesOfItem(atPath: path)
        } <span class="hljs-keyword">catch</span> <span class="hljs-keyword">let</span> error <span class="hljs-keyword">as</span> <span class="hljs-type">NSError</span> {
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"FileAttribute error: \(error)"</span>)
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
    }

    <span class="hljs-keyword">var</span> fileSize: <span class="hljs-type">UInt64</span> {
        <span class="hljs-keyword">return</span> attributes?[.size] <span class="hljs-keyword">as</span>? <span class="hljs-type">UInt64</span> ?? <span class="hljs-type">UInt64</span>(<span class="hljs-number">0</span>)
    }

    <span class="hljs-keyword">var</span> fileSizeString: <span class="hljs-type">String</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-type">ByteCountFormatter</span>.string(fromByteCount: <span class="hljs-type">Int64</span>(fileSize), countStyle: .file)
    }
}
</code></pre>
<p>This is how you can measure your impact:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Screenshot-2020-09-16-at-11.34.24-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Total data saved = n</strong>umber <strong>of request</strong>s <strong><em> video_size = 2.4MB</em>20.3K ~= 49GB</strong></p>
<p>This is just two weeks of data. You do the math for the whole year. ? And this will keep on increasing exponentially over time.</p>
<p>That’s it! You have now built your own caching mechanism.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/yay.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h1 id="heading-wrapping-up">Wrapping up</h1>
<p>In this article, we saw how easily we can integrate multiple videos in one view, giving an Instagram-like story feature.</p>
<p>We also learned why and how caching plays an important role here. We saw how it helps the user save a lot of data and have a smooth user experience.</p>
<p>Do let me know if I missed something, or if you can think of any more use cases.<br>Thanks for your time. :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Get the Identifier For Advertisers (IDFA) in iOS14 ]]>
                </title>
                <description>
                    <![CDATA[ If the title of this article means something to you, then you are probably aware of the earthquake caused by iOS14.  With the release of iOS14, there have been major changes in the way applications can gather information about a user. One of them dea... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-get-the-identifier-for-advertisers-ios14/</link>
                <guid isPermaLink="false">66ba50108e44e0cdf1281252</guid>
                
                    <category>
                        <![CDATA[ Apple ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tomer ]]>
                </dc:creator>
                <pubDate>Tue, 22 Sep 2020 17:44:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/0_oIyg9OzrsA2PiXHW.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If the title of this article means something to you, then you are probably aware of the earthquake caused by iOS14. </p>
<p>With the release of iOS14, there have been major changes in the way applications can gather information about a user. One of them deals with the Identifier For Advertisers (or IDFA) and how applications can access it. </p>
<p>But for those that don't know, let's first explain what the IDFA is and why it's important.</p>
<h2 id="heading-what-is-an-idfa">What is an IDFA?</h2>
<p>Each iOS device owner can decide whether they want to be tracked by advertising companies. This allows those companies to supplying that user with content that is tailored towards them (based on their online browsing habits).</p>
<p>Companies can do this with what’s known as an IDFA (Identifier For Advertisers). This is a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#:~:text=A%20universally%20unique%20identifier%20(UUID,%2C%20for%20practical%20purposes%2C%20unique.) string that lets advertisers match the user with their behavior.</p>
<p>Here's an example of a UUID string : 123e4567-e89b-12d3-a456–426614174000.</p>
<h3 id="heading-so-what-are-those-changes-we-talked-about-earlier">So, what are those changes we talked about earlier?</h3>
<p>In short, applications will now be required to show a dialog to the user, asking them if they want to allow the application to track them or not.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Screen-Shot-2020-09-17-at-22.35.25.png" alt="Image" width="600" height="400" loading="lazy">
<em>The Tracking Authorization Dialog</em></p>
<p>Looks pretty ominous, right?</p>
<p>This is in contrast with how things worked before iOS14, where you only had to check if the device had limited advertising tracking enabled or disabled.</p>
<p>The newest version of Apple’s operating system (iOS14) is already available (has been since September 16th). Developers who use the IDFA have to make changes in their applications in order to be compatible for iOS14. </p>
<p>On September 3rd, Apple made an <a target="_blank" href="https://developer.apple.com/news/?id=hx9s63c5%27">update</a> and pushed the deadline to complete these updates to the start of next year:</p>
<blockquote>
<p>“To give developers time to make necessary changes, apps will be required to obtain permission to track users starting early next year”</p>
</blockquote>
<p>Now that we have some time to regain our composure and breathe again, let’s start preparing ourselves for what’s going to be the new normal in 2021. </p>
<p>In this article, we'll present some background about the IDFA and see how we can get its value from iOS14 and onwards.</p>
<h2 id="heading-how-does-the-idfa-get-used-by-advertisers">How does the IDFA Get Used By Advertisers?</h2>
<p>Let’s take a scenario (pre COIVD-19) where you are browsing the web on your iPhone and are looking for a hotel for your next vacation. </p>
<p>Each ad that you see will send a pixel with your IDFA attached to it. An advertiser can see that you are looking at a lot of ads promoting hotels by matching your IDFA and conclude that you are looking to book a hotel room. </p>
<p>From there, it won’t be long until you will be shown a lot of ads for hotel rooms.</p>
<p>This simple yet profound technology came into our lives back in 2012 with iOS6. Since then a lot has changed, and iOS14 is flipping the industry on its head, yet again.</p>
<p><em>✋</em> Note: <em>To use these new APIs you must have upgraded/downloaded XCode 12</em>.</p>
<h2 id="heading-advertising-tracking-and-getting-the-idfa">Advertising Tracking And Getting The IDFA</h2>
<p>Before iOS14, getting the IDFA was pretty simple.</p>
<p>You had to check whether <a target="_blank" href="https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614148-isadvertisingtrackingenabled">Advertising Tracking</a> was enabled or not, by doing this:</p>
<p><code>[[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]</code></p>
<p>And if it was disabled, that meant you could acquire the IDFA through the <a target="_blank" href="https://developer.apple.com/documentation/adsupport/asidentifiermanager">ASIdentifierManager</a> class, like so:</p>
<p><code>[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];</code></p>
<p>Simple enough, right?</p>
<p><em>☝️ Beginning</em> with <em>iOS10, if the user disabled advertising tracking, the method above would return a UUID string filled with zeros.</em></p>
<p>One of the changes in iOS14 is the deprecation of the method that checks whether advertiser tracking is enabled or not. So how can applications get the coveted IDFA from iOS14 and onward?</p>
<p>They will have to use a new API that presents a dialog to the user. A few words of wisdom regarding this dialog:</p>
<ul>
<li>It can only be presented to the user <strong>once</strong></li>
<li>The only thing that can be altered in the dialog’s UI are the two lines above the Allow Tracking option (<strong>“Do you want to be tracked?”</strong>)</li>
</ul>
<p>This means that developers will need to think long and hard about how and when they will present the message to the user.</p>
<h2 id="heading-authorization-status">Authorization Status</h2>
<p>With iOS14, a new framework has been created called <a target="_blank" href="https://developer.apple.com/documentation/apptrackingtransparency?language=objc">App Tracking Transparency</a>. This framework contains a class called <a target="_blank" href="https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager?language=objc">ATTrackingManager</a>, which provides an API to:</p>
<ol>
<li>Present a dialog to the user requesting permission to track them</li>
<li>Query the authorization status (regardless of showing or not showing the dialog)</li>
</ol>
<p>We’ll first learn how to get the authorization status. To do so, you need to call the <strong>trackingAuthorizationStatus</strong> method.</p>
<p><code>ATTrackingManagerAuthorizationStatus status = [ATTrackingManager trackingAuthorizationStatus];</code></p>
<p>It will return an NSUInteger with one of the following values:</p>
<ul>
<li>ATTrackingManagerAuthorizationStatusNotDetermined = 0</li>
<li>ATTrackingManagerAuthorizationStatusRestricted = 1</li>
<li>ATTrackingManagerAuthorizationStatusAuthorized = 3</li>
<li>ATTrackingManagerAuthorizationStatusDenied = 2</li>
</ul>
<p>The first three results are pretty self explanatory, so we will focus for a minute on the last one. </p>
<p>You can get an authorization status that is restricted when the screen for enabling/disabling advertising tracking is locked and this option is set to enabled.</p>
<p>Apple has acknowledged this in devices that are identified as belonging to children (for example).</p>
<h2 id="heading-asking-for-permission-to-track">Asking For Permission To Track</h2>
<p>Before looking into the code needed to present the dialog, you must first include the <strong>NSUserTrackingUsageDescription</strong> key inside your info.plist file. </p>
<p>What you add as the value for this key will appear as the two lines mentioned earlier, in the dialog.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/Screen-Shot-2020-09-17-at-22.29.31.png" alt="Image" width="600" height="400" loading="lazy">
<em><strong>NSUserTrackingUsageDescription in the info.plist file</strong></em></p>
<p>To present the dialog, we need to call <a target="_blank" href="https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/3547037-requesttrackingauthorizationwith?language=objc">requestTrackingAuthorizationWithCompletionHandler</a>:</p>
<pre><code>[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
        <span class="hljs-keyword">if</span> (status == ATTrackingManagerAuthorizationStatusDenied) {
            <span class="hljs-comment">//Logic when authorization status is denied</span>
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (status == ATTrackingManagerAuthorizationStatusAuthorized) {
            <span class="hljs-comment">//Logic when authorization status is authorized</span>
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (status == ATTrackingManagerAuthorizationStatusNotDetermined) {
            <span class="hljs-comment">//Logic when authorization status is unknown</span>
        }  <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (status == ATTrackingManagerAuthorizationStatusRestricted) {
            <span class="hljs-comment">//Logic when authorization status is restricted</span>
        }
    }];
</code></pre><p>In the first picture of this article (where you see the dialog) you can see that the lines we wrote in the info.plist file show up as the two lines in the dialog.</p>
<h2 id="heading-wrapping-up">Wrapping up</h2>
<p>In conclusion, it's important to remember that these changes, while daunting, are not happening immediately. </p>
<p>You should also make sure to follow all of the steps detailed in this article so as not to come across crashes/errors in your applications.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Top iOS App Development Trends That Will Rule in 2020 ]]>
                </title>
                <description>
                    <![CDATA[ By Roger James Technology has always brought something new with time. And with these ever-changing technologies, you need to stay updated to get all the benefits from what's new. Also, when we talk about technology, one of the first things that proba... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/latest-ios-app-development-trends-2020/</link>
                <guid isPermaLink="false">66d460cdd7a4e35e384349b3</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 04 Mar 2020 18:02:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/02/ui-design-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Roger James</p>
<p>Technology has always brought something new with time. And with these ever-changing technologies, you need to stay updated to get all the benefits from what's new.</p>
<p>Also, when we talk about technology, one of the first things that probably comes to our minds is mobile phones and mobile applications. We are also well aware of the name and fame of iOS devices. And as we've learned from a report from <a target="_blank" href="https://www.aboveavalon.com/notes/2019/5/30/apples-billion-users">Above Avalon</a>, the number of i-Phones in the wild likely now exceeds <strong>925 million.</strong></p>
<p>Now, it's time to look at the top iOS app development trends in 2020. We should take a deep dive into iOS mobile app development trends because iOS has become one of the leading development platforms in the market in recent years. iOS is also supposed to be safer than any other operating system. </p>
<p>We can see all this in these stats from <strong>Statista.com</strong>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/02/--Total-Apple-App-Store-developer-earnings-2020---Statista.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>These statistics show the cumulative Apple App Store earnings of mobile app developers as of January 2020. As of the last reported period<em>,</em> Apple had paid a total of <strong>155 billion U.S. dollars to iOS app developers.</strong> A year ago, this figure amounted to <strong>120 billion U.S. dollars</strong>.</p>
<p>According to <a target="_blank" href="https://www.goodworklabs.com/"><strong>Goodworklabs.com</strong></a>, with an <strong>18%</strong> market share and a combined share of <strong>99.6%</strong> with Android, Apple’s iOS is one of the most happening operating systems of the world.</p>
<p>Well, after going through the various stats and facts, it's time to jump into different trends to watch for iOS app development in 2020.</p>
<h2 id="heading-improved-app-security">Improved app security</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/02/unnamed.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Security features are one of the most helpful and important trends of iOS mobile app development. You might all be aware of Apple's security algorithms. Indeed the company is famous for its hardcore security layers and highly secure policies which help to stop hacks into Apple devices. </p>
<p>Given the number of hacking attacks these days, one mistake can destroy everything. And Apple has around <strong>1.4 billion</strong> active devices.</p>
<p><a target="_blank" href="https://www.forbes.com/sites/zakdoffman/2019/08/30/google-shocks-1-billion-iphone-users-with-malicious-hack-warning/#3ad74a742524">Forbes</a> published an article titled “iPhone Hack: Google Warns <strong>1 Billion Apple Users</strong> They May Have Been Attacked” on 30th Aug 2019. This was just before the launch of iPhone 11 and almost every iOS device was found vulnerable. The vulnerability was fixed in the latest iOS updates.</p>
<p>According to one statement by Phil Schiller, the Senior Vice President of Worldwide Marketing at Apple Inc,</p>
<blockquote>
<p>“(Apple is) helping to protect our children from technologies that could be used to violate their privacy and security.”</p>
</blockquote>
<p>This sheds some light on potential security loopholes. And to help close them, Apple has initiated an enterprise-wide culture that caters to the user’s need to create a safe environment. So their aim is to help improve overall security as well as prevent cyber-attacks and data breaches.</p>
<p><img src="https://lh5.googleusercontent.com/50Q58Gko__ZPIIVHT4CVGPw1moa8RoQFfBoTZp0bA4IUFNGTqSrg9e7cpUnqewksCCba4NBu-tSsawTY6ls0sF8lL4ISczA9bWqWPEt4CYTDY3KD-K6vSt5QPjVdVXWtxMzo7F4s" alt="Image" width="1200" height="620" loading="lazy"></p>
<p>Let’s talk about password auto-fill, for example. Did you know that Apple has deployed <strong>ASWebAuthentication Sessions</strong> which help coordinate cookies and website data for signing in? With this, the device is able to use the authentication service's frameworks in order to incorporate password manager apps.</p>
<h2 id="heading-cloud-integrated-ios-apps">Cloud Integrated iOS Apps</h2>
<p>Cloud technology has brought a revolution to the tech space as well as many opportunities. With the help of cloud technology, organisations can store vast amounts of data in the cloud without any fear of using too much data space. </p>
<p>Because of this, most iOS apps are now built on cloud technology as this is one of the most trustworthy platforms where you can store data. You can also access it anywhere with full security, quickly and easily.</p>
<p><img src="https://lh4.googleusercontent.com/LIcPvJYIqaDvgQjYkJXoTmcnaQwL3zUcu2dM8IFCd5VdTI7cCvi4gP-Qafl-O02j-DuOHGbM6hM8WLXmlVej2VdZLMew5Ag4nwF6VmjTFIjhiLCE79awJmFM48Wh9MW_pT7HvmdA" alt="Image" width="588" height="435" loading="lazy"></p>
<p>You've probably heard about "iCloud" services. This allows iOS device users to store their content without worrying about space. Content stored in iCloud includes stuff like images, files, notes, and much more. </p>
<p>iCloud can be accessed on any device with your login id and password. <strong>According to <a target="_blank" href="https://en.wikipedia.org/wiki/ICloud">Wikipedia</a>, 850 million people trust iCloud.</strong></p>
<p>A significant advantage of having cloud-based apps is that they do not need any physical space in your system, as you can run your data directly on the cloud. </p>
<p>The cloud helps enhance and extend the internal memory of your smart devices. This major feature of cloud-based apps helps increase productivity and collaboration with mobile apps.</p>
<p>This trend is going to revolutionise app development in the coming years.</p>
<h2 id="heading-enterprise-development">Enterprise Development</h2>
<p>Enterprise development is one of the most essential and primary parts of many businesses, and this is why most of the developers prefer to build Enterprise software through iOS.</p>
<p>Enterprise development should be done in a customised way so that the user can get all the benefits. It provides the best user experience, improved security, and high productivity. </p>
<p>This is why most iOS developers trust iOS because it is useful in scalable enterprise development.</p>
<p><img src="https://lh4.googleusercontent.com/qNzk4sPd_5sCsyMWVUzWLXUeS5yB7-MMOe7Kz7OYKvRSJzMDvRaRYQ0PNkT2N1hTnRyGy3eNpAHxbmX13cWD80MKcOSg8Nw0h1NZd3zh7lsYyhuvkTlM9W-DO9WhHahjZn1TH5tZ" alt="Image" width="1200" height="665" loading="lazy"></p>
<p><strong>Source:</strong> <a target="_blank" href="https://www.theverge.com/2019/2/20/18232583/apple-ios-developer-enterprise-program-store-mobile-apps"><strong>The Verge</strong></a></p>
<h2 id="heading-swift-5-programming-language">Swift 5 Programming Language</h2>
<p>The Swift 5 programming language has become quite trendy. Apple has released it with a stable <em>Application Binary Interface (ABI)</em> and binary compatibility. </p>
<p>In addition to ABI, Swift 5 has raw strings, future enum cases, a result type, checking for integer multiples and a lot more. Now iOS app development companies are focusing on using Swift to the best of its abilities for optimal business impact.</p>
<p><img src="https://lh4.googleusercontent.com/i1sBXx5qUrozNZ1gkavaVYGPlLOJvxyXO3pGHHkmPjxLSJjHeWqoOAvMrz8GhubXTf3yeOqbOIjYaUUzXXOT2zLA6wiRIi2_g2pbhXzmSDbM_bvsLNI2saXNozovE8aMrmRxmtdi" alt="Image" width="1600" height="801" loading="lazy"></p>
<p><strong>Source</strong>: <a target="_blank" href="https://9to5mac.com/2019/01/28/apple-swift-5-update-ios-12-2/"><strong>9to5Mac</strong></a></p>
<blockquote>
<p>According to Reddit, “Of the top 110 apps on the app store, 42% are using Swift. If you ignore games, then 57% of the apps are using Swift.”</p>
</blockquote>
<p>Swift libraries will be incorporated into every future <strong>macOS, iOS, Wearable OS,</strong> and <strong>TVOS</strong> device.</p>
<p>Swift 5 is source compatible with Swift 4, Swift 4.1 and Swift 4.2, as well as with X code 10.2. It has a code migration that is designed to handle some of the necessary source changes automatically. </p>
<p>One of the significant advantages of this software is that it is highly compatible with Linux, so it will be easy for developers to increase their knowledge base for Swift 5 when designing apps.</p>
<h2 id="heading-iot-focused-apps">IoT Focused Apps</h2>
<p>There is no doubt that the internet of things has become part of day to day life, so there is no need to introduce it. This technology is becoming more well-known by the day among developers worldwide. </p>
<p>The Internet of Things is a source of communication between you and your smart device. This is why it is creating a revolution.</p>
<p>Today developers are more focused on building iOS apps that, for example, can connect to internet-enabled devices. So we could say that IoT has helped developers create exceptional offerings for users by embedding better connection facilities in their apps.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/02/pasted-image-0.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>There is no doubt that IoT is going to revolutionise the technical world. This is why iOS developers should use this technology as their main tool. It is definitely beneficial and makes things easier for end-users.</p>
<p>Let’s look at an example: pharmaceutical companies use IoT devices to help develop temperature monitoring apps. These apps can detect whether temperatures for certain processes (as desired for the same) do not exceed the allowed limits. So, there are many fields where IoT is leaving its impact with great positivity.</p>
<p>Globally, the number of IoT devices that are active is expected to grow to <strong>10 billion by 2020 and 22 billion by 2025</strong>, says <a target="_blank" href="https://iot-analytics.com/state-of-the-iot-update-q1-q2-2018-number-of-iot-devices-now-7b/">IOT-analytics.com</a></p>
<h2 id="heading-final-words">Final words</h2>
<p>Well, on the basis of this information, you can now see that the above-mentioned iOS app development trends are going to rule 2020. So you should definitely not forget these trends while working on your <a target="_blank" href="https://www.pixelcrayons.com/mobile-app-development/ios-app-development?utm_source=freecodecamp&amp;utm_medium=ios%2Bapp%2Bdevelopment_sk&amp;utm_campaign=website">iOS apps</a> this year.</p>
<p>If you still have questions you can explore this vast topic more. Otherwise, you can leave a comment to let me know how this article helped you.</p>
<p>A related interesting read: <strong><a target="_blank" href="https://www.pixelcrayons.com/blog/top-app-trends-2019/?utm_source=freecodecamp&amp;utm_medium=ios%2Bsk&amp;utm_campaign=website">Top Mobile App Trends For 2020</a></strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to programmatically build a Spotify clone for iOS with AutoLayout ]]>
                </title>
                <description>
                    <![CDATA[ By Said Hayani In this post we will try to re-create the Spotify home screen layout in Swift programmatically. Why programmatically? I think it's always good to know how to build things in different ways, and I like to write code to do things program... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/autolayout-programmatically-spotify-clone-in-swift/</link>
                <guid isPermaLink="false">66d460c9d14641365a050963</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Xcode ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 03 Nov 2019 01:04:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/11/featured_image-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Said Hayani</p>
<p>In this post we will try to re-create the Spotify home screen layout in Swift programmatically. Why programmatically? I think it's always good to know how to build things in different ways, and I like to write code to do things programmatically. These skills are especially helpful if you are working with team or using version control. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/spotify-demo.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This is the actual home screen of Spotify's mobile app. So to achieve this kind of layout, we will be using <code>UICollectionView</code>, and we may use <code>TabBarController</code> as well to create the tab navigator.</p>
<blockquote>
<p>Basic requirement : First  make sure you have Xcode +10 installed and swift +4.</p>
</blockquote>
<p>Let's start by creating a new Xcode project using Xcode:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/Screen-Shot-2019-10-31-at-8.03.13-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And the first thing we need to do in <code>ViewController.swift</code> is change the superClass to <code>UICollectionViewController</code> instead of  <code>UIViewController</code> because our class will be based on <code>collectionView</code>.</p>
<pre><code class="lang-swift"><span class="hljs-comment">//</span>
<span class="hljs-comment">//  ViewController.swift</span>
<span class="hljs-comment">//  spotifyAutoLayout</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">//  Created by admin on 10/31/19.</span>
<span class="hljs-comment">//  Copyright © 2019 Said Hayani. All rights reserved.</span>
<span class="hljs-comment">//</span>

<span class="hljs-keyword">import</span> UIKit

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ViewController</span>: <span class="hljs-title">UICollectionViewController</span> </span>{

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewDidLoad</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.viewDidLoad()
        collectionView.backgroundColor = .purple
        <span class="hljs-comment">// Do any additional setup after loading the view.</span>
    }


}
</code></pre>
<p>If you try to run the app the build will fail. We need to add some code to the <code>AppDelegate.swift</code> file within the <code>didFinishLaunchingWithOptions</code> function past this piece of code before the  <code>return</code> statement:</p>
<pre><code class="lang-swift">  <span class="hljs-keyword">let</span> layout = <span class="hljs-type">UICollectionViewFlowLayout</span>()
        window = <span class="hljs-type">UIWindow</span>()
        window?.rootViewController = <span class="hljs-type">ViewController</span>(collectionViewLayout: layout)
</code></pre>
<p>And the code should look like this:</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">application</span><span class="hljs-params">(<span class="hljs-number">_</span> application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: <span class="hljs-keyword">Any</span>]?)</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-comment">// Override point for customization after application launch.</span>
        <span class="hljs-keyword">let</span> layout = <span class="hljs-type">UICollectionViewFlowLayout</span>()
        window = <span class="hljs-type">UIWindow</span>()
        window?.rootViewController = <span class="hljs-type">ViewController</span>(collectionViewLayout: layout)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
    }
</code></pre>
<p>Now you should be able to run the app and see the <code>backgroundColor</code> changed to <code>purple</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/first-look.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The next step is to distribute the layout and divide the space equally between the sections.</p>
<p>Let's define the methods of our <code>CollectionView</code>.</p>
<p>The steps:</p>
<ul>
<li>Register a reusable cell with unique identifier</li>
<li>Define the number of the items in the section</li>
<li>Use the the registered cell   </li>
</ul>
<p>To use some of <code>CollectionView</code> methods we need to always conform to <code>UICollectionViewDelegateFlowLayout</code> as a superClass and to get the autoComplete of the methods. So let's start with registering the CollectionViewCell.</p>
<p>Inside <code>View.DidLoad()</code> we call the <code>collectionView.register()</code> method to register the reusable cell:</p>
<pre><code class="lang-swift">  collectionView.register(<span class="hljs-type">UICollectionViewCell</span>.<span class="hljs-keyword">self</span>, forCellWithReuseIdentifier: cellId)
</code></pre>
<p>Then we define the number of cells we will have inside the <code>collectionView</code> using <code>numberOfItemsInSection</code>.  For now we just need to make it 5 items:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">5</span>
    }
</code></pre>
<p>The next step is to define the reusable cell using <code>cellForItemAt</code> that should return <code>UICollectionViewCell</code> and have a unique id called <code>cellId</code>. The code looks like this:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath)
        cell.backgroundColor = .red
        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>The full code should look like this:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> UIKit

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ViewController</span>: <span class="hljs-title">UICollectionViewController</span>, <span class="hljs-title">UICollectionViewDelegateFlowLayout</span> </span>{
    <span class="hljs-keyword">let</span> cellId : <span class="hljs-type">String</span> = <span class="hljs-string">"cellId"</span>

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewDidLoad</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.viewDidLoad()
        collectionView.backgroundColor = .purple
        collectionView.register(<span class="hljs-type">UICollectionViewCell</span>.<span class="hljs-keyword">self</span>, forCellWithReuseIdentifier: cellId)

    }


    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">5</span>
    }
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath)
        cell.backgroundColor = .red
        <span class="hljs-keyword">return</span> cell
    }

}
</code></pre>
<p>You should be able to see 5 items with red backgrounds on the screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/cellItem.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-add-a-custom-width-and-height-to-the-cells">Add a custom width and height to the cells</h2>
<p>Now we need to place the cells in the correct order and give them a <code>width</code> and <code>height</code>. Each cell will take the <code>width</code> of the screen as <code>width</code>.</p>
<p>We are lucky to have <code>sizeForItemAt</code> method so we can give the cells a custom <code>width</code> and <code>height</code>. It's a method that should return a <code>CGSize</code> type:</p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">CGSize</span> {
        <span class="hljs-keyword">let</span> width = view.frame.width
        <span class="hljs-keyword">let</span> height = <span class="hljs-type">CGFloat</span>(<span class="hljs-number">200</span>)

        <span class="hljs-keyword">return</span> <span class="hljs-type">CGSize</span>(width: width, height: height)
    }
</code></pre>
<p>So we made the  <code>Cell</code> take the <code>width</code> of the screen by using <code>view.frame.width</code> and a custom <code>height</code> with is a <code>CGFloat</code> type.</p>
<p>Now you can see the result below in your Simulator :</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/Screen-Shot-2019-10-31-at-9.05.46-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Everything looks good so far. This time let's create a custom cell that can be reusable. Create a new Swift file named <code>CustomCell</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/Screen-Shot-2019-10-31-at-11.52.10-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><code>CustomCell.swift</code> should look like this below:</p>
<pre><code class="lang-swift">
<span class="hljs-keyword">import</span> UIKit

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomCell</span>: <span class="hljs-title">UICollectionViewCell</span> </span>{
    <span class="hljs-keyword">override</span> <span class="hljs-keyword">init</span>(frame: <span class="hljs-type">CGRect</span>) {
        <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>(frame: frame)

    }

    <span class="hljs-keyword">required</span> <span class="hljs-keyword">init</span>?(coder aDecoder: <span class="hljs-type">NSCoder</span>) {
        <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"init(coder:) has not been implemented"</span>)
    }
}
</code></pre>
<p>Now the next things we have to do is to modify two methods to support the reusable cell, <code>collectionView.register</code> and <code>cellForItemAt</code>.  Let's first modify the register method. Replace <code>UICollectionViewCell.**self**</code> with <code>CustomCell</code>:</p>
<pre><code class="lang-swift"> collectionView.register(<span class="hljs-type">UICollectionViewCell</span>.<span class="hljs-keyword">self</span>, forCellWithReuseIdentifier: cellId)
</code></pre>
<p>Next we need to cast <code>cellForItemAt</code> to conform to <code>CustomCell</code> like below:</p>
<pre><code class="lang-swift">  <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">CustomCell</span>
</code></pre>
<p>If you run the app probably you won't notice any change, so give the CustomCell a backgroundColor <code>backgroundColor = .yellow</code>. Don't forget to remove the line <code>cell.backgroundColor = .red</code> in <code>cellForItemAt</code>. You should see the background color changed to yellow ?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/Screen-Shot-2019-11-01-at-12.13.20-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now it's time to put some salt into <code>CutomCell</code> :D</p>
<p>If you look at the Spotify home screen, each section which is a <code>CustomCell</code> in our example contains a section title, sub cells, and is horizontal:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/spotify-demo-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-add-a-section-title">Add a section title</h2>
<p>Let's add a title label to the cell. Create the <code>titleLabel</code> element inside the <code>CutomCell</code> class:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">let</span> titleLabel: <span class="hljs-type">UILabel</span> = {
        <span class="hljs-keyword">let</span> lb  = <span class="hljs-type">UILabel</span>()
        lb.text = <span class="hljs-string">"Section Title"</span>
        lb.font = <span class="hljs-type">UIFont</span>.boldSystemFont(ofSize: <span class="hljs-number">14</span>)
        lb.font = <span class="hljs-type">UIFont</span>.boldSystemFont(ofSize: <span class="hljs-number">14</span>)

        <span class="hljs-keyword">return</span> lb
    }()
</code></pre>
<p>Then add the element to the view inside <code>init()</code> block:</p>
<pre><code class="lang-swift">addSubview(titleLabel)
</code></pre>
<p>If you run the app you won't see any changes, and that's because we didn't put any constraint to the element yet. So let's add some constraints – add this property              <code>lb.translatesAutoresizingMaskIntoConstraints = **false**</code> to <code>titleLabel</code> to be able to apply constraints to the element:</p>
<p>After we add <code>titleLabel</code> to the view, we define the constraints:</p>
<pre><code class="lang-swift"> addSubview(titleLabel)
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: <span class="hljs-number">8</span>).isActive = truetitleLabel.leftAnchor.constraint(equalTo: leftAnchor,constant: <span class="hljs-number">8</span> ).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>Always make sure to add <code>.isActive = true</code> property – without it the constraint won't work!        </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/Screen-Shot-2019-11-01-at-12.32.55-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Before we move on to the next part, let's first change the background color of the screen to black and also remove the yellow color for the cells:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/Screen-Shot-2019-11-01-at-12.46.01-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now comes the big part: putting sub cells into each cell. To achieve that we are going to add a <code>CollectionView</code> inside <code>CustomCell</code>.</p>
<p>To add a <code>CollectionView</code> inside <code>UICollectionViewCell</code> we need to add  properties <code>UICollectionViewDelegate</code>, <code>UICollectionViewDelegateFlowLayout</code>, and <code>UICollectionViewDataSource</code> as superClass to <code>CustomCell</code>.</p>
<p>Let's create the <code>collectionView</code> element as any simple view:</p>
<pre><code class="lang-swift">
    <span class="hljs-keyword">let</span> collectionView : <span class="hljs-type">UICollectionView</span> = {
        <span class="hljs-comment">// init the layout</span>
        <span class="hljs-keyword">let</span> layout = <span class="hljs-type">UICollectionViewFlowLayout</span>()
        <span class="hljs-comment">// set the direction to be horizontal</span>
        layout.scrollDirection = .horizontal

        <span class="hljs-comment">// the instance of collectionView</span>

        <span class="hljs-keyword">let</span> cv = <span class="hljs-type">UICollectionView</span>(frame: .zero, collectionViewLayout: layout)

        <span class="hljs-comment">// Activate constaints</span>

        cv.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>

        <span class="hljs-keyword">return</span> cv

    }()
</code></pre>
<p>Notice that we add <code>layout</code> to the <code>collectionView</code> as layer in the initializer as we did the first time with the <code>viewController.swift</code>. Here we also specify the direction of the <code>FlowLayout</code> to be <code>.horizontal</code>.</p>
<p>Let's add the <code>collectionView</code> element to the view as subView.</p>
<p> We gonna make a function that do that for us to make the code a little bit cleaner.</p>
<pre><code class="lang-swift">    <span class="hljs-keyword">fileprivate</span>  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">setupSubCells</span><span class="hljs-params">()</span></span>{
        <span class="hljs-comment">// add collectionView to the view</span>
        addSubview(collectionView)

        collectionView.dataSource = <span class="hljs-keyword">self</span>
        collectionView.delegate = <span class="hljs-keyword">self</span>
        <span class="hljs-comment">// setup constrainst</span>
        <span class="hljs-comment">// make it fit all the space of the CustomCell</span>
        collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = <span class="hljs-literal">true</span>
        collectionView.leftAnchor.constraint(equalTo: leftAnchor).isActive = <span class="hljs-literal">true</span>
        collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = <span class="hljs-literal">true</span>
        collectionView.rightAnchor.constraint(equalTo: rightAnchor).isActive = <span class="hljs-literal">true</span>
    }
</code></pre>
<p>Make sure to set delegate to <code>self</code> for the <code>collectionView</code> and the dataSource as well:</p>
<p>  <code>collectionView.dataSource = self</code></p>
<p>   <code>collectionView.delegate = self</code> </p>
<p>Then call the function within <code>init</code> block.</p>
<p>Xcode will display some errors if you trying to build the app because we are not conforming to <code>UICollectionViewDelegate</code> and <code>UICollectionViewDelegateFlowLayout</code> protocols. To fix that we need first to register the sub cell as a reusable cell.</p>
<p>Create a variable at the top of the class and give it a name of <code>cellId</code> so we can use it when we need the cell identifier: </p>
<p><code>let cellId : String = "subCellID"</code></p>
<pre><code class="lang-swift">collectionView.register(<span class="hljs-type">UICollectionViewCell</span>.<span class="hljs-keyword">self</span>, forCellWithReuseIdentifier: cellId)
</code></pre>
<p>Now we're missing two more methods to make the errors go away: <code>numberOfItemsInSection</code> that define the number of cells in the section and <code>cellForItemAt</code> that define the reusable cell. These methods are necessary for  <code>collectionView</code> to work properly:</p>
<pre><code class="lang-swift"> <span class="hljs-comment">// number of cells</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
       <span class="hljs-keyword">return</span>  <span class="hljs-number">4</span>
    }

    <span class="hljs-comment">// reusable Cell</span>
     <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath)
         cell.backgroundColor = .yellow

        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>The results should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/Screen-Shot-2019-11-01-at-1.40.42-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As you can see, the <code>collectionView</code> are in purple as background and sub cells are yellow.</p>
<p>The last things we can do before ending this article is make <code>subCells</code> have the height of the section and as width. Again we are using <code>sizeForItemAt</code> to define the <code>height</code> and the <code>width</code> of the cell .</p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">CGSize</span> {

        <span class="hljs-keyword">let</span> width = frame.height
        <span class="hljs-keyword">let</span> height = frame.height

        <span class="hljs-keyword">return</span> <span class="hljs-type">CGSize</span>(width: width, height: height)

    }
</code></pre>
<p>And here we are ?:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/complet-layout-demo1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>NICE! I'm gonna stop at this point so this post isn't too long. I'll make a second part where we are going to add some mocked pictures and fill it with some data.</p>
<h3 id="heading-full-source-code-herehttpsgithubcomhayanisaidautolayout-programmatically-in-swift">Full source code ? <a target="_blank" href="https://github.com/hayanisaid/autoLayout-programmatically-in-swift">here</a></h3>
<p>Please please if you have any additions, questions, or corrections, post it in the comments below ? or hit me up on <a target="_blank" href="https://twitter.com/SaidHYN">Twitter</a>.</p>
<p><strong><a target="_blank" href="https://webege.us16.list-manage.com/subscribe?u=311846a57d1e1a666287ad128&amp;id=2b386b2ebb">Subscribe</a></strong> to my email list to be notified when the second part of this tutorial is published </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Your App for iOS 13 Dark Mode ]]>
                </title>
                <description>
                    <![CDATA[ By Shifa Martin Apple launched the much-awaited iOS 13 updates globally on September 19 across all iPhones launched within the past 4 years (back to the iPhone 6s).  One of the biggest features of this update was the system-wide iOS 13 dark mode. It... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-setup-an-app-for-dark-mode-on-ios-13-untitled/</link>
                <guid isPermaLink="false">66d460f88812486a37369d5a</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Apple ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 27 Sep 2019 13:05:01 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/09/app-developer.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Shifa Martin</p>
<p>Apple launched the much-awaited iOS 13 updates globally on September 19 across all iPhones launched within the past 4 years (back to the iPhone 6s). </p>
<blockquote>
<p>One of the biggest features of this update was the system-wide iOS 13 dark mode. It's expected to help with eye-strain caused by white light emitted by smartphone displays.</p>
</blockquote>
<p>While this feature is a joy to end-consumers using Apple devices, it's a task for iOS developers to prepare an app ready for iOS 13 dark mode.</p>
<h2 id="heading-how-to-set-up-your-app-for-ios-13-dark-mode">How to Set up your App for iOS 13 Dark Mode?</h2>
<p>To help developers with this issue, here is useful info and steps showing how they can prep up an existing iOS app for <a target="_blank" href="https://www.apple.com/ae/ios/ios-13/">iOS 13</a> dark mode.</p>
<ul>
<li>It’s not too hard to implement iOS 13 dark mode despite its system-wide scale.</li>
<li>Enabling iOS 13 dark mode on your existing app is also simple mostly thanks to the latest iOS 13 SDK. </li>
</ul>
<p>When using the latest version to build apps for iOS 13 dark mode, the OS will automatically update switches, buttons, and table views among other system controls. Though do note that images and text colors won’t adjust for dark mode automatically.</p>
<p>However, it’s still amazing to see that a system-wide change such as dark mode is so easy to implement. There are smaller code changes and more work that you'll be able to get done with the iOS 13 dark mode in that saved time.</p>
<h2 id="heading-how-to-adapt-colors-for-ios-13-dark-mode">How to Adapt Colors For iOS 13 Dark Mode</h2>
<p>First, let’s start with changing system colors iOS 13 dark mode:</p>
<p>Now there are new system colors added in UIColor, one of which is a label color. Using these new colors helps support dark mode and other high contrast modes in iOS 13.</p>
<pre><code class="lang-js">label.color = UIColor.secondaryLabel
</code></pre>
<p>Generally, you should use system colors for iOS 13 dark mode, which automatically adapts to changes in the interface for maintaining consistency across apps. However, developers can also choose to implement dark mode with custom colors. </p>
<blockquote>
<p>The asset catalog colors introduced with iOS 11 make it much easier to support dark mode by adding dark versions of a custom set of colors. </p>
</blockquote>
<p>You only have to select a preferred color from the catalog, then change Appearances to Any, Dark from the Attributes Inspector. </p>
<p>That's it! Now you have a custom iOS 13 dark mode ready for your mobile app.</p>
<h2 id="heading-troubleshooting-ios-13-dark-mode">Troubleshooting iOS 13 Dark Mode</h2>
<p>Let's say your app is not following iOS 13 dark mode. What will you do? Here are some easy steps to solve this issue.</p>
<h3 id="heading-step-1">Step 1</h3>
<p>You will need to know if the app is updated or not. </p>
<p>If the app is not working with iOS 13 Dark Mode or does not support it, simply update the app via Apple Store.</p>
<h3 id="heading-step-2">Step 2</h3>
<p>Check whether the Dark Mode of your iOS app has been enabled or not. </p>
<p>If not, go to Settings - Display &amp; Brightness - check whether "Dark" is enabled or not.</p>
<h3 id="heading-step-3">Step 3</h3>
<p>If your app is fully updated, but isn't working with iOS 13 Dark Mode, then check the in-app settings. <em>See the image:</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/app-not-following-ios-13s-dark-mode-check-these-settings.w1456-3.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you want more help on setting up your iOS 13 Dark Mode, get it from the <a target="_blank" href="https://www.valuecoders.com/dedicated-development-teams">dedicated development teams</a>. And, that is how I'm going to help you. </p>
<p>Also read tips for <a target="_blank" href="https://www.valuecoders.com/blog/technology-and-apps/11-tips-successful-mobile-app-development-businesses-android-ios/">mobile app development on iOS</a>. Hope all this information will be helpful for you. </p>
<p><em>Let's see what you have to do next.</em></p>
<h2 id="heading-adapt-images-for-ios-13-dark-mode">Adapt Images For iOS 13 Dark Mode</h2>
<p>Most images look great in iOS 13 dark mode, and at times they pop out in a way that really highlights details. However, you may still end up finding some images which look a bit off or unsuitable for dark mode. </p>
<blockquote>
<p>The good news is that you can adjust images for dark mode in the same way text is adjusted. </p>
</blockquote>
<p>All you need to do is select the image in the catalog and as done previously, and change attributes to Any, Dark in the Attributes Inspector. Now add the dark appearance of the image and we’re done.</p>
<h2 id="heading-programmatically-detecting-changes-in-ios-13-dark-mode">Programmatically Detecting Changes in iOS 13 Dark Mode</h2>
<p>Developers could face situations where they need to implement appearance changes in iOS 13 dark mode programmatically. This is how it's done:</p>
<pre><code class="lang-js">override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) 
{
    <span class="hljs-built_in">super</span>.traitCollectionDidChange(previousTraitCollection)

    <span class="hljs-keyword">let</span> userInterfaceStyle = traitCollection.userInterfaceStyle <span class="hljs-comment">// Either .unspecified, .light, or .dark</span>
    <span class="hljs-comment">// Update your user interface based on the appearance</span>
}
</code></pre>
<blockquote>
<p>Overriding traitCollectionDidChange helps in detecting appearance changes.</p>
<p>Then we only have to open traitCollection.userInterfaceStyle.</p>
</blockquote>
<p><strong>You can also verify if the existing appearance is using a new method you just implemented:</strong></p>
<pre><code class="lang-js">override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    <span class="hljs-built_in">super</span>.traitCollectionDidChange(previousTraitCollection)

    <span class="hljs-keyword">let</span> hasUserInterfaceStyleChanged = previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) <span class="hljs-comment">// Bool</span>
    <span class="hljs-comment">// Update your user interface based on the appearance</span>
}
</code></pre>
<h2 id="heading-overriding-the-user-interface-style">Overriding the User Interface Style</h2>
<h3 id="heading-complete-app">Complete App</h3>
<p>The system automatically opts-in any app linked against the iOS 13.0 or later SDK to both light and dark appearances. </p>
<p>If you need extra time to work on your app’s Dark Mode support or want to keep your app in a single style, you can opt-out by including the UIUserInterfaceStyle key (with a value of Light or Dark) in your app’s Info.plist file. </p>
<p>Setting this key causes the system to ignore the user’s preference and always apply the specific appearance to your app.</p>
<blockquote>
<p><strong>Note:</strong> Supporting iOS 13 Dark Mode is strongly encouraged. Use the UI UserInterfaceStyle key to opt-out only temporarily while you work on improvements to your app’s Dark Mode support.</p>
</blockquote>
<h3 id="heading-specific-screens">Specific Screens</h3>
<p>In iOS 13, you can now override the user interface style on specific views or view controllers. For example, you may want only a certain view controller to be in iOS 13 dark mode, while the rest of your app is in light mode.</p>
<p>To override the user interface style, just override this variable in the top view or view controller and it will propagate down to sub-views:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Inside a UIViewController</span>
override func viewDidLoad() 
{
    <span class="hljs-built_in">super</span>.viewDidLoad()

    <span class="hljs-comment">// Always adopt a dark interface style.    </span>
    overrideUserInterfaceStyle = .dark
}
</code></pre>
<h3 id="heading-closing-notes">Closing Notes</h3>
<p>Thanks for reading the article! Here we've explored how to set up an app for iOS 13 dark mode. </p>
<p>iOS 13 dark mode brings with it a unique stress-free way to use a smartphone. Perhaps we’ll see a future where dark mode replaces the default mode with the whiter backgrounds. </p>
<p>By following these coding guidelines and tips you can easily set up your app for dark mode on iOS 13. </p>
<p><strong>If you need some expert help, feel free to g<a target="_blank" href="https://www.valuecoders.com/contact">et in touch</a> with <a target="_blank" href="https://www.valuecoders.com/hire-developers/hire-ios-developers">iOS developers</a> for iOS 13 dark mode related queries.</strong>   </p>
<p><strong>F</strong>ollow on Twitter for<strong> more </strong>updates:<strong> </strong><a target="_blank" href="https://twitter.com/ValueCoders">https://twitter.com/ValueCoders</a><em>**</em>  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Developer Checklist: What should you not miss from WWDC 2019? ]]>
                </title>
                <description>
                    <![CDATA[ By Boudhayan Biswas So it’s almost near about one month already since WWDC 2019 happened this year. All the developers are still busy what are new things Apple has added or updated for development. There were some big announcements and small announce... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/developer-checklist-what-should-you-not-miss-from-wwdc-2019/</link>
                <guid isPermaLink="false">66d45ddc7df3a1f32ee7f7eb</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ wwdc ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 30 Jun 2019 03:50:31 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/06/danielle-macinnes-222441-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Boudhayan Biswas</p>
<p>So it’s almost near about one month already since WWDC 2019 happened this year. All the developers are still busy what are new things Apple has added or updated for development. There were some big announcements and small announcements, but we, the developers need to make sure that we won’t miss anything important. So I am just creating a quick checklist of the items what we should not miss. Let’s make it short, concise and simple.</p>
<h3 id="heading-ios">iOS:</h3>
<ol>
<li>iOS 13 will let you limit application location access to just once. Until now, there were three options — “Always”, “While Using” or “Never”. One more option has been added to this list “Just Once”. For the first time, you can share your location to an app — just once — and then require it to ask you again next time it wants.</li>
<li>Might be one of the popular announcements and people are going crazy about this. Yes, I am talking about “Apple Sign-in”. So it is a requirement from Apple that app developers must implement the company’s new single sign-in solution if the app already offers another third party sign in.</li>
<li>You can dismiss modal view controllers interactively which may break some of the existing applications. On iOS 13, by default, the user can just swipe the modal down to dismiss it. So when you are developing a new application make sure to take this into consideration. You can disable this behaviour by <code>_isModalRepresentation = false_</code>.</li>
<li><code>UISegmentedControl</code> and <code>UIStepper</code> are different in iOS 13 with a whole new updated design.</li>
<li>A new update to <code>Localization</code> in iOS 13. From now, the user can set a different language to each of the application installed in your device. Developers have nothing to change or consider regarding the development, <code>Settings</code> application will take care on behalf of you.</li>
<li>iOS 13 has almost 1500 different system icons and <code>UIImage</code> got a new initializer <code>UIImage(systemName: )</code> with this you can now initialize any of the system icons.</li>
<li>Until now when you download something in Safari that directly goes into <code>downloads</code> folder, but this year Safari got an update and you can change the default download folder to any other folder you want, even you can choose USB drive also.</li>
<li>Improvements to <code>UIStoryboardSegue</code>. Apple has introduced a new <code>IBSegueAction</code> modifier. Now you can pass additional context and parameters directly to the destination view controller that should be initialized.</li>
<li>Your apps can provide reservation information to Siri with context and at specific times so the user can take relevant actions based on the circumstances. For example, they can confirm a hotel reservation, be reminded to check in for a flight and get help returning a rental car.</li>
<li>With Core NFC framework, your apps can now support tag writing, including writing to NDEF formatted tags. The framework also provides support for reading and writing tags using native protocols such as ISO 7816, MIFARE, ISO 15693, and FeliCa.</li>
<li>Synch your Core Data store with CloudKit, giving users of your app seamless access to their data across all their devices. Core Data with CloudKit combines the benefits of local persistence with cloud backup and distribution.</li>
<li>Metal gives the GPU even greater control of the graphics and compute pipeline, adds features that make it easier to perform advanced GPU processing, and simplifies the work you need to do to support different kinds of GPUs. New tools, including Metal support in Simulator, help you get started faster and understand whether your iOS app is using Metal correctly.</li>
<li>With the new VisionKit framework, your app can let users scan documents using the device’s camera, like those you capture in the Notes app. Combine this feature with Vision’s text recognition to extract text from scanned documents.</li>
<li>Core ML 3 now supports on-device model personalization, allowing you to update a model by retraining or fine-tuning it with user-specific data privately from within your app. Core ML has also greatly expanded its support for dynamic neural networks with over 100 layer types.</li>
<li>The new PencilKit framework makes it easy to incorporate hand-drawn content into your app quickly and easily. PencilKit provides a drawing environment for your iOS app that takes input from Apple Pencil, or the user’s finger, and turns it into high-quality images you display in either iOS or macOS. The environment comes with tools for creating, erasing, and selecting lines.</li>
<li>MetricKit is a new framework that gives you on-device power and performance metrics about your app captured by the system, which you can use to improve the performance of your app.</li>
<li>The new Core Haptics framework that lets you compose and play haptic patterns to customize your app’s haptic feedback.</li>
<li>Use the new Apple CryptoKit framework to perform common cryptographic operations securely and efficiently, such as Computing and comparing cryptographically secure digests, Using public-key cryptography to create and evaluate digital signatures, Generating symmetric keys, and using them in other operations like message authentication and encryption.</li>
<li>Combine is a new framework that provides a declarative Swift API for processing values over time. These values can represent user interface events, network responses, scheduled events, and many other kinds of asynchronous data. With Combine, you declare publishers that expose values that can change and subscribers that receive those values from the publishers. Combine makes your code easier to read and maintain, by centralizing your event-processing code and eliminating troublesome techniques like nested closures and convention-based callbacks.</li>
<li>Keep your app content up-to-date and perform long-running tasks while your app is in the background using the new BackgroundTasks framework.</li>
<li>RealityKit is a new Swift framework to simulate and render 3D content for use in your augmented reality apps including the ability to add animation, physics, and spatial audio to your AR experience. RealityKit leverages information provided by ARKit to seamlessly integrate virtual objects into the real world.</li>
<li>Symbol images give you a consistent set of icons to use in your app, and ensure that those icons adapt to different sizes and to app-specific content. Symbol images use the SVG format to implement vector-based shapes that scale without losing their sharpness. They also support many traits typically associated with the text, such as weight and baseline alignment.</li>
<li>With iOS 13, the user can create and manage multiple instances of your app’s user interface simultaneously and switch between them using the app switcher. On iPad, the user can also display multiple instances of your app side by side. Each instance of your UI displays different content or displays content in a different way. For example, the Calendar app can display the appointments for a specific day and for an entire month side by side.</li>
<li>SwiftUI is a modern approach to building user interfaces for iOS, macOS, watchOS, and tvOS. You can build dynamic interfaces faster than ever before, using declarative, composition-based programming. The framework provides views, controls, and layout structures for declaring your app’s user interface. It also provides event handlers for delivering taps, gestures, and other types of input to your app, and tools to manage the flow of data from your app’s models down to the views and controls that users will see and interact with.</li>
<li>When the Voice Control Accessibility feature is turned on, there’s a blue microphone icon at the top of the device to indicate that the iOS device is in Voice Control mode. The dimmed icon when the phone doesn’t have your attention.</li>
<li>One of the new features in iOS 13 is an option in the Files app to connect to the server using SMB. This feature wasn’t working in the first beta but is functional in beta 2, so iOS 13 users can do things like connecting to a home NAS.</li>
<li>When sharing a webpage from the Safari Share Sheet, there are new options to share it as a PDF or a Web Archive. There’s also an “Automatic” option that picks the most suitable format for each app or action.</li>
<li>No more spam callers. iOS 13 now supports strictly silencing unknown callers.</li>
<li>In iOS 13, we got a new method on <code>UIImageAsset</code> named <code>registerImage:withTraitCollection</code> that can be used to create dynamic images for light and dark programmatically.</li>
<li>Running on Low Mobile data? A new “Low Data” mode has been added to avoid running out of data when you’re on a roaming plan.</li>
<li>When we do not have wifi then sometimes we face difficulty in downloading apps which are bigger in size. But after iOS 13, we can see a ray of light there. Now the limit has increased to 200 MB, still not enough? Then you can remove the restriction in Settings.</li>
<li>Share photo to others with original information in it. iOS 13 is giving you an option to add that original information when sharing.</li>
<li>Be happy to mute your iPhone. Apple has introduced a new completely redesigned mute indicator to match Apple pencil charging indicator.</li>
<li>Now you can initialize UIViewController subclasses with additional context and arguments (required for dependency injection).</li>
<li>If you are not a delegate fan then there are some good news for you. iOS 13 has updated some delegate based APIs to block based API.</li>
<li>You do not need to long press on any app and tap on the cross icon to delete. Now you can simply remove an app from AppStore update page by a left swipe.</li>
<li>Until now screenshot was taken only in image format. iOS 13 allows you to take a screenshot in pdf format also.</li>
<li>iOS 13 has a new <code>_visualRecursiveDescription</code> private API that can construct a visual representation of a view hierarchy. Very useful command for debugging in LLDB.</li>
<li>A new <code>UICollectionViewCompositionalLayout</code> class has been added to UIKit to make it easier to create compositional layouts without requiring a custom <code>UICollectionViewLayout</code>.</li>
<li>The <code>UITableViewStyle</code> enum gained a new public <code>UITableViewStyleInsetGrouped</code> case that can be used to create grouped style table views.</li>
<li>iOS apps using the File Management APIs can now be granted read/write access to an entire folder, rather than just a file.</li>
<li>Tired of swiping in scroll view? In iOS 13, you can drag the scroll indicator to go through a long document.</li>
<li>Apps intended for kids cannot include third-party advertising or analytics software and may not transmit data to third parties.</li>
<li>MDM provides access to sensitive data, MDM apps must request the mobile device management capability, and may only be offered by commercial enterprises, such as business organizations, educational institutions, or government agencies, and, in limited cases, companies utilizing MDM for parental controls. MDM apps may not sell, use, or disclose to third parties any data for any purpose, and must commit to this in their privacy policy. (referring to apps that abused MDM for Screen Time-like features).</li>
</ol>
<p>Yeah, it’s quite a long list fully filled with new features. Developers can use all of them to make their application better and smoother. Now let’s take a look at the new frameworks that are coming with iOS 13-</p>
<h3 id="heading-frameworks">Frameworks:</h3>
<ol>
<li><strong>BackgroundTasks</strong>: Use the BackgroundTasks framework to keep your app content up to date and run tasks requiring minutes to complete while your app is in the background. Longer tasks can optionally require a powered device and network connectivity. Register launch handlers for tasks when the app launches and schedule them as required. The system will launch your app in the background and execute the tasks.</li>
<li><strong>Combine:</strong> The Combine framework provides a declarative Swift API for processing values over time. These values can represent user interface events, network responses, scheduled events, and many other kinds of asynchronous data. Combine declares <em>publishers</em> to expose values that can change over time, and <em>subscribers</em> to receive those values from the publishers.</li>
<li><strong>CoreAudioTypes:</strong> The CoreAudioTypes framework declares common data types and constants used by other Core Audio interfaces. This framework also includes a handful of convenience functions.</li>
<li><strong>Core Haptics:</strong> Core Haptics lets you add customized haptic and audio feedback to your app. Use haptics to engage users physically, with tactile and audio feedback that gets attention and reinforces actions. Some system-provided interface elements — like pickers, switches, and sliders — automatically provide haptic feedback as users interact with them. With Core Haptics, you extend this functionality by composing and combining haptics beyond the default patterns.</li>
<li><strong>QuickLookThumbnailing</strong>: You may want to create a miniature representation, or <em>thumbnail</em>, of a file and its contents to display within your app, or to provide a thumbnail to the operating system. For example, macOS shows thumbnails as part of the Finder app and its Quick Look feature. The QuickLookThumbnailing framework provides an API to generate thumbnails for common file types using the <code>QLThumbnailGenerator</code> object.</li>
<li><strong>PencilKit</strong>: PencilKit makes it easy to incorporate hand-drawn content into your iOS or macOS apps quickly and easily. PencilKit provides a drawing environment for your iOS app that takes input from Apple Pencil, or the user’s finger, and turns it into high-quality images you display in either iOS or macOS. The environment comes with tools for creating, erasing, and selecting lines.</li>
<li><strong>RealityKit</strong>: Use the RealityKit framework to implement high-performance 3D simulation and rendering. RealityKit leverages information provided by the ARKit framework to seamlessly integrate virtual objects into the real world.</li>
<li><strong>VisionKit</strong>: VisionKit is a small framework that lets your app use the system’s document scanner. Present the document camera as a view controller, which covers the entire screen like the camera function in Notes.</li>
<li><strong>SoundAnalysis</strong>: Use the SoundAnalysis framework to analyze audio and recognize it as a particular type, such as laughter or applause. The framework performs its analysis using a Core ML model trained by an <code>MLSoundClassifier</code>. Using the framework’s ability to analyze streamed or file-based audio lets you add intelligent audio recognition capabilities to your app.</li>
<li><strong>CryptoKit</strong>: Use Apple CryptoKit to perform common cryptographic operations: Compute and compare cryptographically secure digests. Use public-key cryptography to create and evaluate digital signatures, and to perform the key exchange. In addition to working with keys stored in memory, you can also use private keys stored in and managed by the Secure Enclave. Generate symmetric keys, and use them in operations like message authentication and encryption. Prefer CryptoKit over lower-level interfaces. CryptoKit frees your app from managing raw pointers, and automatically handles tasks that make your app more secure, like overwriting sensitive data during memory deallocation.</li>
<li><strong>Maps Web Snapshots</strong>: The Maps Web Snapshots service can be used to generate static map images from a URL. You can use Snapshots any time that an interactive map is not required, and in any place, you typically use an image URL — in web pages, and in places where JavaScript is not available, such as email clients.</li>
<li><strong>DriverKit</strong>: Use DriverKit to create device drivers that the user installs on their Mac. Drivers built with DriverKit run in userspace, rather than as kernel extensions, for improved system security and stability.</li>
<li><strong>MetricKit</strong>: With MetricKit, you can receive on-device app power and performance metrics captured by the system. A registered app receives reports containing data about the previous 24 hours at most once per day. Use the data in the reports to help improve the performance of your app.</li>
<li><strong>SystemExtensions</strong>: Creating system extensions allow your app to enhance the capabilities of the user’s Mac, without the associated risks of developing kernel extensions (KEXTs). System extensions run in userspace, where they can’t compromise the security or stability of macOS. The system grants these extensions a high level of privilege, so they can perform the kinds of tasks previously reserved to KEXTs.</li>
<li><strong>EndpointSecurity</strong>: Use the Endpoint Security library to create security-related software. Endpoint Security clients monitor system events for potentially malicious activity. Your client registers with Endpoint Security to authorize pending events, or receive notifications of events that have already occurred. These events include process executions, mounting file systems, forking processes, and raising signals.</li>
<li><strong>USBSerialDriverKit</strong>: The USBSerialDriverKit framework provides an API for developing serial communication drivers for USB devices like modems and serial adapters. The framework builds on DriverKit by adding the ability to set attributes like baud rate and parity and work with a device’s universal asynchronous receiver/transmitter (UART).</li>
<li><strong>USBDriverKit</strong>: Use the USBDriverKit framework to develop drivers for custom or non-class compliant USB devices for use with macOS. USBDriverKit provides C++ classes you can use to attach and configure your device and create USB message and stream pipes to exchange data. USBDriverKit devices work with the core types defined in the DriverKit framework.</li>
<li><strong>HIDDriverKit</strong>: The HIDDriverKit framework provides C++ classes for developing drivers for human interface devices: keyboards, pointing devices, and digitizers like pens and touchpads. HIDDriverKit uses the core types defined in DriverKit, and adds features specific to human interface device development.</li>
</ol>
<p>That’s all for today. Happy coding!!</p>
<p><strong><em>???Thank you for reading???</em></strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to setup a helpful auto-complete UITextField using CoreData in Swift ]]>
                </title>
                <description>
                    <![CDATA[ By Emrick Sinitambirivoutin All you need to know to build your autocompletion search bar with a UITableView and CoreData. _Photo by [Unsplash](https://unsplash.com/@grohsfabian?utm_source=medium&utm_medium=referral" rel="noopener" target="_blank" ti... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-an-autocompletion-uitextfield-using-coredata-in-swift-dbedad03ea3d/</link>
                <guid isPermaLink="false">66c351231283974fd2bb0790</guid>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ UX ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 20 Feb 2019 19:27:25 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*qC1j-oZGtDOy3lYhYaWbHA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Emrick Sinitambirivoutin</p>
<h4 id="heading-all-you-need-to-know-to-build-your-autocompletion-search-bar-with-a-uitableview-and-coredata"><em>All you need to know to build your autocompletion search bar with a UITableView and CoreData.</em></h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*nzfy7hZivPO7PeN6" alt="Image" width="800" height="562" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@grohsfabian?utm_source=medium&amp;utm_medium=referral" rel="noopener" target="_blank" title=""&gt;Fabian Grohs on &lt;a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral" rel="noopener" target="<em>blank" title=")</em></p>
<p>In this article, I’m going to present how I built a custom search field with an autocompletion feature to retrieve data from CoreData. It’s a component that I needed in one of my apps and that can be very useful in many cases to improve the user’s experience.</p>
<h4 id="heading-we-will-see">We will see:</h4>
<ul>
<li>How to set up a simple app with a search UITextField</li>
<li>How to configure a TableView to show the search results</li>
<li>How to make real-time queries to CoreData collections</li>
</ul>
<h3 id="heading-1-setting-up-the-project">1. Setting up the project</h3>
<p>Just create a single view App with the following components (check CoreData at the project creation !). To be more concrete, let’s imagine this is for a travel recommendation App and the user needs to provide a city name to get all the information of the place.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*lxJev437cZZQtFP8zQ2few.png" alt="Image" width="691" height="1232" loading="lazy"></p>
<p><strong>UILabel :</strong> We will call it <em>topLabel.</em> We won’t need it.</p>
<p><strong>UITextField:</strong> It’s the field that we will customize to have an autocomplete search field, so let’s call it <em>searchTextField.</em></p>
<p><strong>UIButton :</strong> It’s the button that will be pressed when the user will find the place that they want. Let’s call it <em>searchButton</em>.</p>
<p>The tableView will be added programmatically so that you will see how to set it up in any kind of situation.</p>
<p><em>To have a beautiful render, I added an UIImageView on the background with a wonderful beach image.</em></p>
<p>To connect all those components to our View Controller, select each of them and drag their reference using (<strong>Control (or Ctrl) ⌃ + Click</strong>) to your main View Controller swift file.</p>
<h3 id="heading-2-configure-our-customsearchtextfield-class">2. Configure our CustomSearchTextField class</h3>
<p>To create our new class, we create a new file called <em>CustomSearchTextField.swift.</em> It’s in this class, that inherits from UITextField, that we will embed all the features that we need to implement our autocompletion search field.</p>
<h4 id="heading-creating-the-tableview-with-the-results">Creating the TableView with the results:</h4>
<p>To be able to show the completion results, we need to instantiate a UITableView that will display the most relevant results as below:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*Fi0M9cyXLSiMkhZihagKIg.png" alt="Image" width="746" height="736" loading="lazy"></p>
<p>To do so we need to create a tableView object and then add it to the current view. In order to handle this new object, we need to override specific methods as shown below. All of the code needed to build the searchTableView will be handled by this method: <em>buildSearchTableView()</em>.</p>
<p>Instantiating the tableView is as simple as creating a new UITableView object, but in order to access all of the functionalities of this new tableView object, we need to inherit from the TableViewDelegates and the TableViewDataSource methods. It is important to pay attention to two important variables:</p>
<ul>
<li><strong>The tableView delegate:</strong> This variable will let us specify which object of the view needs to be informed when some changes occur in the tableView (in our case, this object is our SearchTextField which is in this context the <em>self</em> object)</li>
<li><strong>The tableView DataSource:</strong> This variable will let us specify how all the components of the tableView will be created and from which data. Here again, we need to set it to <em>self</em>.</li>
</ul>
<p>Setting those two variables allows us to handle some actions related to the UITableView within our CustomSearchTextField class.</p>
<p>Now that the table view is created, we need to add data in it, and more concretely, this data will be stored into cells. We use methods inherited from the TableViewDataSource class to configure our cells and to add them to the tableView. In addition to this, the TableViewDelegates’ method will allow us to trigger where the user clicks and will print the content of the corresponding cell in the console.</p>
<p>But if you try to run the code above, nothing will happen because the tableView frame is not set and we didn’t bring the view to the front. In order to fix this, we now need to add a <em>updateTableView()</em> method:</p>
<p>Our TableView is set and is now supposed to work perfectly! But at this time we have to add data in our dataList if we want to display something. To do it simply for now, we will just add dummy data to our list: the text that the user enters in our search bar.</p>
<p>But the main goal of all of this is to give our users autocompletion results while they are typing in our search bar, so we need to observe when the user types a new letter and to update the tableView data according to that.</p>
<p>As you can see above, we modified the <em>willMove()</em> method in order to set how to handle each of the user interactions with the textField. The one that interests us is when the text field changes (when the user is typing). So each time that this action is activated, we add data to our list and we update our tableView.</p>
<h4 id="heading-improving-the-user-experience">Improving the user experience:</h4>
<p>Even if our searchField doesn’t search at all, you must have seen that when we type and the results are starting to show up, all of the results are in plain text. This doesn’t look that much like an autocompletion search bar. To be more user-friendly, it would be nice to highlight the part of the text that we already typed in the text field and also to filter the results so that they correspond to what we are actually typing. <strong>Let’s do this</strong> ?</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*qC1j-oZGtDOy3lYhYaWbHA.png" alt="Image" width="744" height="677" loading="lazy"></p>
<p>It’s time to create our filter method. This method will filter the relevant items from the dataList (the ones corresponding to what the user starts typing). We will use <em>NSMutableAttributedString class</em> to be able to highlight the part of the text that the user typed in the text field<em>.</em></p>
<p>First, we create a <em>SearchItem</em> class that will represent each of our filtered results. As we are building our wonderful travel recommendation app, we will consider that those items are city names. Here is the <em>SearchItem</em> class:</p>
<p>We now need to change our global variable and to add a new one to store our filtered items:</p>
<p>Then let’s create our filter method:</p>
<p>By converting our string to an <em>NSString</em>, we can use the method <em>range() that</em> returns the range of the first occurrence of a given string within the string. By using this method we both know if the string corresponds to what the user is typing and the position of the corresponding string! That’s all we need to highlight this part of our item. We do this using <em>setAttributes</em> methods and we then add our item to the resultsList. Finally, we reload the data in our tableView.</p>
<p>Let’s create new test data to try our implementation:</p>
<p>Everything should work perfectly, we’re almost done! ?</p>
<h3 id="heading-3-make-queries-to-coredata">3. Make queries to CoreData</h3>
<p>It’s nice to have a beautiful search bar with a custom table view to display our autocompletion filtered results, but without data, it’s not very useful ?.</p>
<p>Let’s connect our search text field to CoreData storage.</p>
<h4 id="heading-create-a-coredata-database">Create a CoreData database:</h4>
<p>In order to store our persistent data, we will create a new entity (table) in our database with two attributes (rows). To do so we click to the .xcdatamodeld file in the file explorer and create a new entity named Cities, add the two attributes that we need: cityName and countryName.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*E2fkTUHuGvS0utH3PFAZtw.png" alt="Image" width="800" height="352" loading="lazy">
<em>CustomSearchField..xcdatamodeld</em></p>
<p>Then we will modify the type of our dataList in <em>CustomSearchField.swift</em> to be a list of Cities instead of a list of SearchItems:</p>
<pre><code><span class="hljs-keyword">var</span> dataList : [Cities] = [Cities]()
</code></pre><h4 id="heading-make-queries-to-the-created-database">Make queries to the created database:</h4>
<p>Now we need to create some methods to handle the saving and the fetching of new data in the database. To do so we need to create a context. The context is a specific zone where we will store all of our changing before committing them to the database. If you use git, this is like the staging zone. You first add your file to the staging area, and when you are ready with your changes you commit them to your git.</p>
<p>We change the beginning of our <em>filter()</em> method in order to query the data that corresponds to the user input instead of fetching all the data from the database:</p>
<p>The last thing to add is a new <em>addData()</em> method to populate our database. Be careful, this function needs to be called only one time as the data stored will become persistent, so comment the corresponding line in your code (just before the creation of the tableView in <em>buildSearchTableView()</em> ) after the first call! Even if the app is restarted, the data will still be available in the internal memory of the device.</p>
<h3 id="heading-thats-it-were-done">That’s it ! We’re done ! ?</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*6XJ4ermJVit_NYHatv6loQ.gif" alt="Image" width="260" height="468" loading="lazy"></p>
<p>I started to dive into Swift programming a few weeks ago with an interesting MOOC that I found on Udemy. After I had acquired the basics of Swift and Xcode development, I began to work on my own projects with all of the useful documentation that I found on the web. This first tutorial is an opportunity for me to share all that knowledge that I acquired, so I hope that it has helped you!</p>
<p>If you have a question don’t hesitate to tell me in the comments! And don’t forget to give me a clap if you enjoyed the article ???</p>
<p>All the final project code is available here:</p>
<p><a target="_blank" href="https://github.com/sinitame/customSearchField-medium"><strong>sinitame/customSearchField-medium</strong></a><br><a target="_blank" href="https://github.com/sinitame/customSearchField-medium">_Source code for Medium article : How to create an autocompletion UITextField using CoreData in Swift …_github.com</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use Auto Layout with UIScrollView for iOS ]]>
                </title>
                <description>
                    <![CDATA[ By Sam Ollason I love building tools with software, and that is why I am currently the Lead Developer for Green 13 Solutions. Recently I have been having lots of fun using Swift and the Interface Builder in Xcode to create iOS apps. I ran into some c... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-auto-layout-with-uiscrollview-for-ios-b94b8687a4cc/</link>
                <guid isPermaLink="false">66c3559aa6c3eebadae8d2df</guid>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 25 Jan 2019 16:16:06 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*rWN6HdC61ChO2dNs8W8wEQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Sam Ollason</p>
<p>I love building tools with software, and that is why I am currently the Lead Developer for <a target="_blank" href="http://irisd.green13solutions.com/">Green 13 Solutions</a>.</p>
<p>Recently I have been having lots of fun using Swift and the Interface Builder in Xcode to create iOS apps.</p>
<p>I ran into some challenges when I was trying to create a <strong>scene</strong> where users can <strong>scroll</strong> to see content that overflows in the current <strong>content view</strong>. The content wasn’t scrolling properly and the text wasn’t automatically being shown properly for different screen sizes.</p>
<p>Here are some notes for my future self to refer to. I hope you find them useful as well!</p>
<p>Here is a <a target="_blank" href="https://github.com/SamOllason/autolayout-scrollview-example">repository</a> for the project if you want to see the completed example.</p>
<h3 id="heading-what-we-will-build">What we will build</h3>
<p>Our app will have a single page. The page will contain some text and users can scroll down to see the text that overflows from their current content view.</p>
<p>We will use the Interface Builder in Xcode to add a UIScrollView object, a nested UIView object and then a further nested UITextView object. We will use the Interface Builder to add constraints to these elements. The constraints will mean that Auto Layout can enable scrolling to happen properly and the Text View will automatically appear properly on different screen sizes.</p>
<h3 id="heading-a-swift-bit-of-background-info-pun-intended">A swift bit of background info (pun intended)</h3>
<p>The UIScrollView object can be used as a parent object to other UIKit items such as UIView and UITextView.</p>
<p>Doing this means that all child objects can <strong>collectively have their origin shifted</strong> relative to the <strong>content view</strong> that is shown to the user. This means ‘scrolling’ behaviour works as users expect. Another benefit is that Auto Layout will properly size our elements on different screens as expected.</p>
<p>We use the terms ‘UIScrollView’ and ‘Scroll View’ interchangeably below, and similarly for View and Text View.</p>
<p>Below are the steps to follow.</p>
<h3 id="heading-adding-view">Adding View</h3>
<p>Create new project and selecting ‘Single View App’. If you click on Main.storyboard and you will see we have a scene with a blank View element.</p>
<h3 id="heading-adding-scroll-view">Adding Scroll View</h3>
<p>Drag a Scroll View UI element from the Object Library into the scene. Then add the constraints shown in the picture below to anchor the Scroll View element to the edges of its parent Safe Area.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Jhaxfl2emel8kPk8TwfmUSLlJSoPciBhfibi" alt="Image" width="578" height="694" loading="lazy"></p>
<h3 id="heading-add-a-view-element">Add a View element</h3>
<p>Use the Object Library to drag a View element into the scene. The View will be the parent container for our Text View element.</p>
<p>Manually resize the View element with your cursor so that it fills the width of the screen.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/MKboKx-1Pr9cG-z5Po9jigJc6BK01-TororP" alt="Image" width="800" height="679" loading="lazy">
<em>Manually resized View element to fit into width</em></p>
<h3 id="heading-anchor-view-to-scroll-view">Anchor View to Scroll View</h3>
<p>Click on the View element in the object hierarchy and drag+release your cursor onto the Scroll View element above it in the hierarchy. Click on the 4 topmost options to apply these constraints. Click on the ‘Equal Widths’ to apply this constraint also.</p>
<p><strong>Why?</strong> Constraining the View this way means that a child Text View element we add works properly with Auto Layout. This happens because we constrain the Text View to the bottom of the View (which we anchored properly to the bottom of the Scroll View!) instead of directly to the bottom of the Scroll View.</p>
<p>You will see that the layout guides in the Interface Builder are red because there is some other error. We will fix this shortly.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/cGgPMQiJhTMXXpSUXQYKFP9uiKqDNkonUiJw" alt="Image" width="800" height="598" loading="lazy">
<em>Add these constraints to the View element</em></p>
<h3 id="heading-add-text-view-as-child-to-view">Add Text View as child to View</h3>
<p>Add a Text View element inside the View element in the scene.</p>
<h3 id="heading-add-constraints-to-the-text-view">Add constraints to the Text View</h3>
<p>Add the constraints in the picture below to the Text View.</p>
<p><strong>Why?</strong> This will constrain the Text View relative to the View object that is surrounding it.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/NhKkvtmYB37I7gGULPDI-a7idl2KWN7mlcex" alt="Image" width="542" height="704" loading="lazy">
<em>Adding constraints to Text View</em></p>
<h3 id="heading-disable-scroll-behaviour-in-text-view">Disable scroll behaviour in Text View</h3>
<p>You should have a similar screen to the one below. You can see that there is still a lot of red in the Interface Builder.</p>
<p>You can remove these warnings by selecting the Text View element and <strong>deselecting the ‘Scrolling Enabled’ in the editor pane</strong> on the right hand side.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/C2yKd3qiiQtqIVmO4A5FV7oCpMuB9KyFaevK" alt="Image" width="800" height="463" loading="lazy">
<em>Deselect ‘Scrolling Enabled’ on the right to remove these red errors</em></p>
<p>Note that we will still have scroll behaviour with this approach but <strong>it will be the parent Scroll View that is actually being moved, not the individual Text View element</strong>. Its the same as how a leaf only moves on a river because the river that surrounds it is moving!</p>
<p>This is slightly subtle but quite important to understand as it underpins the whole solution.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/JjCnsnOxlF0Cp5akdGf9wDrOvWUexcPe9jXd" alt="Image" width="800" height="533" loading="lazy">
<em>Our approach means a Text View only scrolls because a Scroll View moves it — same as how a leaf only moves because the surrounding river moves it</em></p>
<h3 id="heading-finally">Finally</h3>
<p>Add some more content to the Text View. You should see that scrolling works as expected and that the Text View appears properly on different screen sizes.</p>
<p>This is the beauty of Auto Layout!</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/YuajWxyO9HnRMGpONlOhgGA7iXZ5wOajtCqL" alt="Image" width="800" height="1271" loading="lazy">
<em>Screenshot of scrolled Text View using Xcode Simulator</em></p>
<p>Here is a <a target="_blank" href="https://github.com/SamOllason/autolayout-scrollview-example">repository</a> for the project if you want to see the completed example.</p>
<p>All information about robins for the Text View content is directly from <a target="_blank" href="https://en.wikipedia.org/wiki/European_robin">Wikipedia</a>. Thanks to the community for this.</p>
<p><em>Why robins?</em> Because I love birds and robins are particularly awesome creatures!</p>
<p>Thanks for reading, I hope you found this useful. Please let me know if you have any comments of questions!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to get your app featured on the App Store ]]>
                </title>
                <description>
                    <![CDATA[ By Marie Denis I’m a Swift developer and indie maker. I have made several apps, and they’ve been featured on the App Store every time. Threader, a Twitter client that curates good threads and displays them on a single page, even became featured as Ap... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-get-featured-on-the-app-store-c056e62a7e7a/</link>
                <guid isPermaLink="false">66c35229bc39b1419091be46</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 08 Jun 2018 15:55:48 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*0q5tzOOEFxCQeUxB4GbAKw.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Marie Denis</p>
<p>I’m a Swift developer and indie maker. I have made several apps, and they’ve been featured on the App Store every time. <a target="_blank" href="http://threader.app/">Threader</a>, a Twitter client that curates good threads and displays them on a single page, even became featured as <a target="_blank" href="https://itunes.apple.com/us/story/id1367658799">App of the Day</a>.</p>
<p>Here is some advice from my experience that might help Apple consider your app for promotion as well.</p>
<p><em>Note: Although this advice applies to all app categories, the game category is a bit more specific. I won’t cover the game app category in particular in this post.</em></p>
<h3 id="heading-how-to-get-featured-in-the-new-apps-we-love-section">How to get featured in the “New Apps We Love” section</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/51URO5y-jDk6vGtGizP4ZbMjo1udgzA6aTsK" alt="Image" width="576" height="1024" loading="lazy">
<em>Threader featured in “New Apps We Love”</em></p>
<h4 id="heading-a-clean-app"><strong>A clean app</strong></h4>
<p>Of course, the first thing to consider is how to make a bug free app with a clean design. Think design, UX, and wording among other things. Don’t forget to test it (different devices, different OS, different people…).</p>
<p>Make things homogenous: use the same set of fonts and colors everywhere. Avoid text when you can. Don’t reinvent the wheel, especially if you’re not a designer. Use the standard iOS items: buttons, navigation bar, and so on.</p>
<p>It’s not always possible, but it can be useful to see people use your app. If you see that they’re not using it as expected or don’t manage to perform certain actions, then you might need to review your UX.</p>
<h4 id="heading-use-apples-apis">Use Apple’s APIs</h4>
<p>Apple promotes their own products. They’ll be more inclined to feature an app that uses the latest Swift version and uses their own APIs. In 2017 they released ARKit and made a special category on the App Store to promote the apps using it.</p>
<h4 id="heading-extensions">Extensions</h4>
<p>Although I don’t have solid proof of this, Apple likes when you take advantage of all their platforms. Think of iMessage, share &amp; action extensions, and so on.</p>
<p>For example, Threader has an action extension. It allows you to open a thread directly from Twitter and read it on a single page, just like on the app. It’s an extension of the main app. It’s useful and allows certain actions outside of it, without opening it.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/WoCWRONqwYtqzMY9FbvgKRmjSaQIpEE6L8KE" alt="Image" width="628" height="1080" loading="lazy">
<em>Threader’s action extension to read a thread directly from Twitter</em></p>
<h4 id="heading-great-visuals">Great visuals</h4>
<p>All the information about your app is important and plays a role in getting featured. You can (re)read <a target="_blank" href="https://medium.com/@marie_dm_/submit-publish-your-app-on-the-app-store-bb4e68258c41">my previous article</a> explaining how to submit an app. There’s some useful info in there (like the “Prepare for submission” and “App previews &amp; screenshots” sections). The most important thing is your visuals. Make something clean, simple to understand, and with fewer words…</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/9yKf9wINKY3Bt2tLDGOGwDE9XMoXKDg0QtoP" alt="Image" width="800" height="343" loading="lazy">
_Threader’s screenshots on the [App Store](https://itunes.apple.com/us/app/threader-for-twitter/id1317519091" rel="noopener" target="<em>blank" title=")</em></p>
<h4 id="heading-frequent-updates">Frequent updates</h4>
<p>Apple likes frequent updates. Users like frequent updates. This doesn’t mean you need to create a new feature every day. But fix bugs, get feedback from your users, and push updates regularly.</p>
<p>Frequent updates are also recommended if you want to stay featured longer and stay on the top of the App Store. I push an update every two days or so when I’m featured. About once a week when I’m not.</p>
<h4 id="heading-ios-only">iOS only</h4>
<p>If your app is only available on iOS (meaning no Android version), I recommend you mention it. I suspect Apple likes exclusivity.</p>
<h4 id="heading-ratings">Ratings</h4>
<p>Apple introduced a way to reply to users’ reviews on <a target="_blank" href="https://appstoreconnect.apple.com/">iTunes Connect</a>. It’s useful to thank the good ones, but also to understand what went wrong for the bad ones and reply to those as well.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/qahK2ab2Ynp-2z0VPOqG4cY86DLYxutXZL4D" alt="Image" width="800" height="470" loading="lazy">
<em>Reply to users’ reviews</em></p>
<h4 id="heading-localizations">Localizations</h4>
<p>Translate your app into different languages. Especially if your app is available in several countries. Apple will appreciate that you took the time to do it.</p>
<p>It’s an annoying task, and localization is pretty hard to update. That’s why you should do it in the latest possible phase of your app development. I hope Apple will improve this one day, since it’s really painful.</p>
<h4 id="heading-keywords-amp-search-results">Keywords &amp; search results</h4>
<blockquote>
<p>ASO (App Store Optimization) is the process of improving the visibility of a mobile app […] in an app store. — [Wikipedia](wiki: https://en.wikipedia.org/wiki/App_store_optimization)</p>
</blockquote>
<p>That’s why you need to choose your keywords carefully. I use <a target="_blank" href="https://www.appannie.com/fr/">App Annie</a> sometimes to check the quality of my app’s keywords.</p>
<h4 id="heading-finally-the-most-important-step-fill-out-the-form"><strong>Finally, the most important step:</strong> Fill out the form</h4>
<p>There’s actually a <a target="_blank" href="https://developer.apple.com/contact/app-store/promote/">form to fill out</a> to contact the App Store Editorial Team to get promoted.</p>
<p>Important to note: “please let us know <strong>6–8 weeks in advance</strong>”. So think about it way before you submit your app. Especially for iOS where the market is way more crowded than the macOS market, for example.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0couDSX7s8Up384gNpv5bvVL9-rHHfuVAUkj" alt="Image" width="800" height="932" loading="lazy">
_[Contact form](https://developer.apple.com/contact/app-store/promote/" rel="noopener" target="<em>blank" title=") to fill out in advance</em></p>
<p>For me, the two most important fields in the form are:</p>
<ul>
<li>The “App Details / Describe your app” section</li>
<li>Your Story</li>
</ul>
<p>Globally, this is like sending your resume to Apple for an application. Sell your app and yourself (or your dev team).</p>
<h3 id="heading-the-holy-grail-how-to-be-app-of-the-day">The Holy Grail: How to be App of the Day</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/7SzFVaRlAECaaQ4rpRRfwJoAeDCZ1mfVITb4" alt="Image" width="750" height="884" loading="lazy">
_[Threader featured as App of the Day](https://itunes.apple.com/us/story/id1367658799" rel="noopener" target="<em>blank" title=")</em></p>
<p>If you get featured, then Apple might consider making your app the App of the Day or featuring it in the App/Game tab. If that’s the case, you’ll receive an email. You’ll have to produce several pieces of artwork/visuals and submit them via iTunes Connect.</p>
<p>A few pieces of advice from my one-time-being-App-of-the-Day experience:</p>
<ul>
<li>Be creative and look at the other Apps of the Day to give you an idea of what they look like.</li>
<li>Carefully follow <a target="_blank" href="https://help.apple.com/itc/appspromoart/"><strong>their guidelines</strong></a> for the artwork</li>
<li>Respect the deadlines</li>
<li>Consider releasing your app worldwide if that’s not already your plan. If you’re featured as App of the Day, you will get featured in all the countries where your app is available.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/iMIlpmrqqUiXvNTw2a4fTRAMcSSXG15GXBeu" alt="Image" width="800" height="498" loading="lazy">
<em>Promotional Artwork section on iTunes Connect</em></p>
<p>Just so you know, even <strong>if you submit your artwork, it doesn’t mean Apple is going to feature</strong> you. I know. You worked hard on this. And it might lead to nothing.</p>
<p>Also, after you’ve submitted your artwork, you probably won’t get any news from Apple about the status of your app. You just wait. And that’s it.</p>
<p>Let’s take my example: our apps have been considered two times for promotion. Both times we provided the artwork. Both times we waited for weeks. Both times we didn’t get any news. We didn’t get any replies to our emails. One app did not get featured. <a target="_blank" href="https://threader.app">The other</a> has been App of the Day. Without notice.</p>
<h3 id="heading-additional-general-advice">Additional general advice</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/hmSBxlrcnfX5n2kqz-dRO9jtAZ1ByX0mQd3T" alt="Image" width="800" height="533" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/photos/82TpEld0_e4?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;G. Crescoli on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h4 id="heading-the-competition">The competition</h4>
<p>Remember that the <strong>iOS App Store</strong> is very <strong>crowded</strong>. A lot of apps go out every single day. For example, I published <a target="_blank" href="https://ipman.io">IP Man</a> (a Mac menu bar app to easily copy/paste your IP) to the Mac App Store. Even though I didn’t respect the deadline of ‘6–8 in advance’ (I know I didn’t respect my own guidelines), they featured it. And I can tell you it helps a lot with sales.</p>
<p>The Mac App Store is a good place to sell apps. There are way fewer apps available, so there is less competition. That’s likely why IP Man got featured.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/DvV3MQq2amcWM86Xri3HYR8ADD8h4AJM78xD" alt="Image" width="800" height="500" loading="lazy">
_[IP Man](https://ipman.io/" rel="noopener" target="<em>blank" title=") featured in “New Apps We Love” on the Mac App Store</em></p>
<h4 id="heading-who-are-your-competitors">Who are your competitors</h4>
<p>Another piece of advice I can give you is to <strong>look at your competitors</strong> who have been featured, and other featured apps in general. I’m not saying all apps look the same, but there is definitely a pattern. Sell your app the Apple way. Use their vocabulary and their design style.</p>
<p>Note, though: You don’t have to say everywhere that your app is “insanely great”.</p>
<p>What you can do: on the App Store, go on the central bottom ‘Apps’ tab. Scroll until you find ‘Top Categories’ and click on ‘See All’. Now you see all the categories. Select the ones your app is in and navigate through the top apps: these are you competitors.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/tisE3EFVrRj8s8uhUVrJgQkUycFVj0AF6TrA" alt="Image" width="800" height="474" loading="lazy">
<em>Check your competitors on the App Store</em></p>
<p>You can also check the Today tab and see the last week’s Apps of the Day. This gives you at least 6 examples.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/IuBUNrvQZWtN7rr2GsnbsogqF0ggPifLP6Ov" alt="Image" width="750" height="1334" loading="lazy">
<em>The Today tab on the App Store</em></p>
<h4 id="heading-you-dont-actually-know-ifwhen-youll-get-featured">You don’t actually know if/when you’ll get featured</h4>
<p>Apple doesn’t notify you. So like us, you’ll just notice a pickup of new users. You’ll check where they came from, not understanding what is happening. Then check the App Store to see if you are featured. And celebrate.</p>
<h3 id="heading-useful-links-to-become-an-app-store-feature-master">Useful links to become an App-Store-Feature Master</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/CQhm3mzFSN9BHnbuX-YWUl1y-GpXlYcPKc0j" alt="Image" width="800" height="469" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/photos/YLSwjSy7stw?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Alfons Morales on &lt;a href="https://unsplash.com/search/photos/reading?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<ul>
<li><a target="_blank" href="https://developer.apple.com/app-store/discoverability">Discovery on the All-New App Store</a>, especially the last section “Getting featured”.</li>
<li>I highly recommend you read <a target="_blank" href="https://developer.apple.com/app-store/product-page/">Making the Most of Your Product Page</a>. It explains how to fill out your app information and also gives you an overview of how it looks on the App Store. You even have more links for some of the sections.</li>
<li><a target="_blank" href="https://developer.apple.com/app-store/app-previews/">Show More with App Previews</a> for those of you who use video previews.</li>
<li><a target="_blank" href="https://developer.apple.com/app-store/search/">Optimizing for App Store Search</a>, useful for choosing your keywords.</li>
<li><a target="_blank" href="https://developer.apple.com/app-store/planning/">Make the Most of the App Store</a>, especially the first section “Build your App Store Presence”.</li>
<li><a target="_blank" href="https://developer.apple.com/contact/app-store/promote/">The form</a> to fill out to get promoted.</li>
</ul>
<p>In general, <strong>follow Apple’s guidelines.</strong> I think it’s the most important. If you think of any other rules/tips, please let me know! I’ll add it with your name :)</p>
<hr>
<p><a target="_blank" href="https://twitter.com/marie_dm_">I’m on Twitter</a> if you want to see if my next apps will be featured or not. ??</p>
<p><a target="_blank" href="https://mailchi.mp/80a197d266d6/twomakers">Subscribe</a> to my blog <a target="_blank" href="https://twomakers.io">TwoMakers.io</a> to receive updates about my journey.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Everything you’ve always wanted to know about notifications in iOS ]]>
                </title>
                <description>
                    <![CDATA[ By Payal Gupta Pretty Little Alerts..? Notifications are a way to inform users when new data becomes available for their apps, even when the app is not running in the foreground. For example, a messaging app might let the user know when a new messag... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/ios-10-notifications-inshorts-all-in-one-ad727e03983a/</link>
                <guid isPermaLink="false">66c3586fcf1314a450f0d6da</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 04 Jun 2018 16:54:51 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*KCLG3VkqwWXdgV2CXwp3Kg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Payal Gupta</p>
<h4 id="heading-pretty-little-alerts">Pretty Little Alerts..?</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*KCLG3VkqwWXdgV2CXwp3Kg.jpeg" alt="Image" width="800" height="533" loading="lazy"></p>
<p>Notifications are a way to inform users when new data becomes available for their apps, even when the app is not running in the foreground.</p>
<p>For example, a messaging app might let the user know when a new message has arrived, and a calendar app might inform the user of an upcoming appointment.</p>
<p>With the release of <strong>iOS-10,</strong> Apple introduced brand new frameworks to support notifications, be it local or remote. This release was focused on <strong>customized notifications</strong>.</p>
<p>Without wasting any time, let’s just quickly jump in to the details.</p>
<h3 id="heading-types-of-notifications">Types of notifications</h3>
<p>We can broadly classify notifications into two categories:</p>
<ul>
<li><strong>Local notifications</strong> — the app configures the notification details locally and passes those details to the system. The system then handles the delivery of the notification when the app is not in the foreground.</li>
<li><strong>Remote notifications</strong> <em>—</em> you use one of your company’s servers to push data to user devices via the Apple Push Notification service (APNs).</li>
</ul>
<p>Further down in the article, we’ll see how we can get ahold of both notification types. Let’s first start with an introduction to this new notification framework that we can use for our cause.</p>
<h3 id="heading-whats-new-in-ios-10-for-notifications">What’s new in iOS-10 for notifications?</h3>
<p>With the release of <strong>iOS-10</strong>, Apple introduced two new frameworks to handle notifications:</p>
<ul>
<li><a target="_blank" href="https://developer.apple.com/documentation/usernotifications"><strong>User Notifications Framework</strong></a> — manages both local and remote notifications.</li>
<li><a target="_blank" href="https://developer.apple.com/documentation/usernotificationsui"><strong>User Notifications UI Framework</strong></a> — customizes the appearance of the system’s notification interface.</li>
</ul>
<p>We’ll be using these two frameworks and some platform-specific APIs to configure our notifications.</p>
<p>Along with the frameworks, the <a target="_blank" href="https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension"><strong>Notification service app extension</strong></a> was also introduced that allows you to modify the content of remote notifications before they are delivered.</p>
<p>Apple also allows customizing your notification’s UI though the <a target="_blank" href="https://developer.apple.com/documentation/usernotificationsui/customizing_the_appearance_of_notifications"><strong>Notification content extension</strong></a><strong><em>.</em></strong></p>
<p>Is it too much to remember? Yup...surely it is. But, don't worry. We’ll see everything step-by-step along with the relevant code. Just take it easy. ?</p>
<h3 id="heading-first-things-first-configure-it">First things first — configure it!</h3>
<h4 id="heading-request-authorization">Request Authorization</h4>
<p>To get our app to notify the user of anything, we need to know whether the person using it actually wants that in the first place. Mayby they don’t like their phone ringing and displaying alerts all the time ? or maybe they actually want the updates, but not that irritating sound…naahhh!☠️</p>
<p>So, first of all we need to get permission from the user we’re going to notify. And that’s pretty simple — just two lines of code and we’re done:</p>
<p>You need to write that code in <code>AppDelegate’s</code> method — <code>application:didFinishLaunchingWithOptions:</code>before returning from it.</p>
<p><strong>Please note:</strong> Because the system saves the user’s response, calls to <code>[requestAuthorization(options:completionHandler:)](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649527-requestauthorization)</code> method during subsequent launches do not prompt the user again.</p>
<h4 id="heading-adding-categories-and-actions-actionable-notifications">Adding Categories and Actions — Actionable Notifications</h4>
<p>The user notifications framework supports adding categories and actions to the notifications.</p>
<p><strong>Categories</strong> — Define the types of notifications that the app supports and communicate to the system how we want a notification to be presented.</p>
<p><strong>Actions</strong> — Each category can have up to four actions associated with it. Actions are basically custom buttons, that on tap dismiss the notification interface and forward the selected action to the app for immediate handling.</p>
<p>Okayyy! And what does that mean..??? Some code might help you understand better:</p>
<p>In the above code, we simply created a category named INVITATION with four different actions — <strong>remindLater</strong><em>,</em> <strong>accept</strong><em>,</em> <strong>decline</strong><em>,</em> and <strong>comment</strong>.</p>
<p>The categories and actions are uniquely identified by their identifiers. Whenever a notification with a category is delivered, the system presents the notification along with all the actions associated with that category once the user expands it. This is what it will look like: ?</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*RAR8fwTQ_py7jtqmr7-zUw.png" alt="Image" width="500" height="540" loading="lazy"></p>
<p>Define all the categories and actions just below where you configured notifications in <code>application:didFinishLaunchingWithOptions:</code> method.</p>
<p>Include the category identifier (eg. INVITATION) when scheduling your notification whether locally or remotely. We’ll see how to do that in the next section.</p>
<h3 id="heading-scheduling-local-notifications">Scheduling local notifications</h3>
<p>Now that we’re done with configuring our notifications, let’s see how to actually schedule one <strong>from within the app</strong>.</p>
<p>Scheduling a local notification requires just three simple steps:</p>
<ol>
<li>Prepare the content</li>
<li>Add a trigger — when the notification should be fired</li>
<li>Schedule it for delivery</li>
</ol>
<p>Let’s get on with the code quickly, so we don’t get confused with everything happening here. LOL ?</p>
<p>In the above code, along with the other content, we have also provided a <code>categoryIdentifier</code> to support actionable notifications. In case we don’t do that, the system will adopt it’s default behavior.</p>
<p>That’s it. That’s all that’s needed. And yes it definitely works...hehehe.? Give it a try before moving on any further. You can download the sample from h<a target="_blank" href="https://github.com/pgpt10/Notifications">ere.</a></p>
<p><strong>Please note</strong>: Apps behave differently in background and foreground states whenever a notification is delivered.</p>
<ol>
<li><strong>App not running / App in Background</strong> — the system displays local notifications directly to the user. We don’t get any callback in the app for that.</li>
<li><strong>App in Foreground</strong> — the system gives the app the opportunity to handle the notification internally. <em>The system silences notifications for foreground apps by default</em>.</li>
</ol>
<p>When the app is in foreground while the notification is delivered, we get the callback in <code>[UNUserNotificationCenterDelegate](https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate)'s</code> method — <code>[userNotificationCenter(_:willPresent:withCompletionHandler:)](https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate/1649518-usernotificationcenter)</code> where you can decide whether to handle the notification silently or alert the user about it.</p>
<p>Don’t forget to conform <code>AppDelegate</code> to <code>UNUserNotificationCenterDelegate</code> protocol and setting it as the delegate of <code>[UNUserNotificationCenter](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter)</code> shared object in <code>application:didFinishLaunchingWithOptions:</code>.</p>
<pre><code><span class="hljs-keyword">let</span> center = UNUserNotificationCenter.current()
</code></pre><pre><code>center.delegate = self
</code></pre><p>We’re done with local notifications for now. Let’s move on to how we can schedule a notification from outside our app. Before that, let’s have a look at how to respond to the custom actions.</p>
<h4 id="heading-responding-to-user-actions">Responding to User Actions</h4>
<p>Configuring notifications? ✔ Scheduling notifications? ✔</p>
<p>What about tapping a notification or any custom action in the notification? Where will it lead? In both the cases, the system notifies the app of the user’s choice.</p>
<p>Whenever the user performs any action in the notification, the response is sent to <code>UNUserNotificationCenterDelegate's</code> method — <code>[userNotificationCenter(_:didReceive:withCompletionHandler:)](https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate/1649501-usernotificationcenter)</code>, where we can provide handling specific to each action.</p>
<p><strong>Please note:</strong> if the app is not running when a response is received, the system launches the app in the background to process the response.</p>
<h3 id="heading-remote-notifications">Remote notifications</h3>
<p>Push notification or remote notifications, no matter what we call them, are one of the most frequently used with lots and lots of use-cases.</p>
<p>Be it social media or calendar or any of the utilities apps, we can see them almost everywhere. From news apps notifying us of the latest content, to Medium itself alerting us of the latest published articles.</p>
<p>Ever wonder how do they even do that? Local Notifications ?? It could be…it does the same thing — right? Maybe we can do some more configuration in the local one itself and get that working?</p>
<p>But Medium, for example, don’t have access to the app on our personal device, so how could it schedule any notifications? Exactly! It can’t. This is something different and something more than just the local ones.</p>
<p>Ok, how about we send the notification from some point and show it at some other point — will this answer our question? Yup, it surely will. But how to do that? <strong>Remote Notifications</strong> it is.</p>
<p>This is exactly what they do. This is the feature that has solved THE BIG PROBLEM of “Keeping up-to-date”.</p>
<h4 id="heading-terminology"><strong>Terminology</strong></h4>
<ul>
<li><a target="_blank" href="https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1"><strong>APNs</strong></a> <strong>—</strong> the centerpiece of the remote notifications feature. It is a cloud service that allows approved third-party apps installed on Apple devices to send push notifications from a remote server to users over a secure connection.</li>
<li><strong>Device Token —</strong> An app-specific token that is globally unique and identifies one app-device combination. It enables communication between the Provider, APNs, and the Device.</li>
<li><strong>Provider —</strong> Server that actually sends the remote notification including the device token and other information to APNs.</li>
</ul>
<p><strong>Important note</strong>: <strong>Never cache device tokens in your app.</strong> Instead, get them from the system when you need them.</p>
<p>APNs issues a new device token to your app when certain events happen. The device token is guaranteed to be different, for example, when a user restores a device from a backup, when the user installs your app on a new device, and when the user reinstalls the operating system.</p>
<p>When you attempt to fetch a device token but it has not changed, the fetch method returns quickly.</p>
<p><strong>Please note:</strong> The ability of APNs to deliver remote notifications to a non-running app requires the app to have been launched at least once.</p>
<h4 id="heading-how-it-actually-works"><strong>How it actually works</strong></h4>
<p>Below is a small and quick explanation of how all the above technologies work together in sync to complete the remote notifications workflow.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*RC5Ahc9Lj2LHrTWTQ8XxVQ.png" alt="Image" width="800" height="133" loading="lazy"></p>
<ol>
<li><strong>App</strong> registers with <strong>APNs</strong></li>
<li><strong>APNs</strong> sends device token to <strong>Device</strong> with then sends it to <strong>App</strong></li>
<li><strong>App</strong> sends this device token to <strong>Provider</strong></li>
<li><strong>Provider</strong> sends notifications with that device token to <strong>APNs</strong> which then sends it to <strong>Device</strong> which then sends it to the <strong>App</strong>.</li>
</ol>
<p>If a notification for your app arrives with the device powered on but with the app not running, the system can still display the notification. If the device is powered off when APNs sends a notification, APNs holds on to the notification and tries again later.</p>
<h4 id="heading-handle-it-in-the-app">Handle it in the app</h4>
<p>Now that we are aware of what remote notifications are and what things are needed to make them work, let’s now move on to how we can make our app support them. Because nothing happens on its own ?. We need to make some configurations for them to work.</p>
<p>To be able to handle remote notifications, our app must:</p>
<ol>
<li><strong>Enable remote notifications in capabilities</strong> — just one-click and you are done with this step. In the <strong>Capabilities</strong> tab of our Xcode project, enable the <strong>Push Notifications</strong> option. Ensure that Push Notifications is added to the App ID that we are using for the project.</li>
</ol>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*jxD3SJUZFNwwN6iUpNgCIA.png" alt="Image" width="800" height="278" loading="lazy"></p>
<p><strong>2.</strong> <strong>Register with Apple Push Notification service (APNs) and receive an app-specific device token</strong></p>
<p>Requesting to register with APNs is quick and easy. Just add the below code in <code>UIApplicationDelegate’s</code> method— <code>application:didFinishLaunchingWithOptions:</code> before returning from it.</p>
<pre><code>UIApplication.shared.registerForRemoteNotifications()
</code></pre><p>Now there are two possibilities: either we get registered successfully or the process fails.</p>
<p>On successful registration, APNs sends an app-specific device token to the device in<code>UIApplicationDelegate’s</code> method— <code>[application:didRegisterForRemoteNotificationsWithDeviceToken:](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application?language=objc)</code>.</p>
<p>In case of faliure, we receive a callback in <code>UIApplicationDelegate’s</code> method—<code>[application:didFailToRegisterForRemoteNotificationsWithError:](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622962-application?language=objc)</code>.</p>
<p><strong>3. Send the device token to notification provider server</strong></p>
<p>As of now, we’ve received the device token from APNs<em>.</em> Now, we need to send this token to our provider, which will use it while pushing any notifications to our device.</p>
<p>Since we don’t have a provider, for now we can use <a target="_blank" href="https://itunes.apple.com/us/app/easy-apns-provider-push-notification-service-testing-tool/id989622350?mt=12">Easy APNs Provider</a> for testing our push notifications. Further down, we’ll see how exactly we can make use of this tool.</p>
<p>For now, just download and install it on your Mac.</p>
<p><strong>4. Implement support for handling incoming remote notifications</strong></p>
<p>We have our device token, and our provider also knows about it. Next, the Provider will send the notification including this token and other information in it, and we’ll get it on our device.</p>
<p>Now what? What will happen when it arrives? How will it appear on the device? What will happen when we tap on it? What about all the actions that we configured earlier? Can we get them here?</p>
<p>Too many question ❓❓❓Well, don’t worry. We’ll have answers to all of them one-by-one.</p>
<p><strong>What will happen when it arrives?</strong> We’ll get a callback in <code>UIApplicationDelegate’s</code> method— <code>[application(_:didReceiveRemoteNotification:fetchCompletionHandler:)](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application)</code>. It tells the app that a remote notification has arrived that indicates there is data to be fetched.</p>
<p><strong>How will it appear on the device?</strong> It will appear with the default notification interface. If the notification’s <strong>payload</strong> is configured with <strong>category</strong><em>,</em> it will appear as the actionable notification with all the actions attached to that category. We’ll discuss the payload in next section.</p>
<p><strong>What will happen when we tap on it?</strong> Same as local notifications. <code>UNUserNotificationCenterDelegate's</code> method — <code>[userNotificationCenter(_:didReceive:withCompletionHandler:)](https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate/1649501-usernotificationcenter)</code> is called with the response object.</p>
<h4 id="heading-handle-it-on-the-provider">Handle it on the Provider</h4>
<p>We have covered most of the things we need to integrate push notifications into our app. Although we know how to handle them in the app, we are still short of handling them on the provider.</p>
<p>We have the provider. It knows what device token to use, but that alone won’t pop up a notification on our device with some title and other details. Neither will it make any of the actions appear.</p>
<p>So, pushing notifications from the provider requires the following items:</p>
<ol>
<li>A <strong>device token</strong></li>
<li><strong>APNs certificate</strong> <em>—</em> we can obtain it from the developer account</li>
<li><strong>Payload</strong> — any custom data that you want to send to your app, and includes information about how the system should notify the user. It’s simply a <strong>JSON dictionary</strong> with some key value pairs. The below illustration might help you understand it better.</li>
</ol>
<p>Let’s see what’s all in that <strong>JSON dictionary</strong>:</p>
<ol>
<li><strong>aps</strong> <strong>dictionary</strong> — the most important one. Contains <strong>Apple-defined keys</strong> and is used to determine how the system that is receiving the notification should alert the user.</li>
<li><strong>alert</strong> <strong>dictionary</strong> — it is more of a self-explanatory item. Provides the content of the notification.</li>
<li><strong>category</strong> — for actionable notifications. All the actions attached to that category will be available in the notifications.</li>
<li><strong>content-available</strong> <em>—</em> To support a background update notification, set this key to 1.</li>
<li><strong>mutable-content</strong> — To enable a notification’s modification through <strong>Notification Service App Extension</strong>, set it to 1.</li>
</ol>
<p><a target="_blank" href="https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW1">Here</a> you can read more about customizing the payload as per your requirements. <a target="_blank" href="https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1">This</a> is a reference to the keys that we can add in the aps dictionary</p>
<h3 id="heading-notification-service-app-extension"><strong><em>Notification Service App Extension</em></strong></h3>
<p>At this point, we know what <strong>remote notifications</strong> are, how they work, what all we need to get them working — pretty much everything! Since we just got them working perfectly✌️.</p>
<p>Now the question is, what if we want to modify some content in the notification received from the provider, before presenting it on the device? What if the notification contains some image link that we need to download before delivering it to the user? Can we do that with what we already know? We don’t have access to the provider…so how will we?</p>
<p>We can’t actually. <strong>We can’t change what we get, but we can definitely change what we present.</strong></p>
<p>That’s what <strong>Notification Service App Extension</strong> is all about— modifying the content of remote notifications before delivery. It is as simple as it looks. No fancy code, nothing. It’s really very simple.</p>
<h4 id="heading-adding-notification-service-extension-to-the-project">Adding Notification Service Extension to the project</h4>
<p>Extensions in an xcode project are added as a target. Select <strong>File</strong> — <strong>New</strong> — <strong>Target</strong> — <strong>Notification Service Extension.</strong></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*_p2o1WUXo-0YX_uL8iAs1A.png" alt="Image" width="800" height="574" loading="lazy"></p>
<h4 id="heading-prerequisites">Prerequisites</h4>
<p>Before we begin to modify the content, there are some restrictions on when the content is allowed to be modified.</p>
<p>Content can be modified only if:</p>
<ul>
<li>The remote notification is configured to display an alert.</li>
<li>The remote notification’s <strong>aps dictionary</strong> includes the <strong>mutable-content</strong> key with the value set to 1.</li>
</ul>
<p>We cannot modify silent notifications or those that only play a sound or badge the app’s icon.</p>
<p>So, to support any modifications in the notifications’ content, these conditions must be fulfilled.</p>
<h4 id="heading-modifying-the-content"><strong>Modifying the content</strong></h4>
<p>The default notification service extension target provided by Xcode contains a subclass of the <code>[UNNotificationServiceExtension](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension)</code> class for us to modify.</p>
<p>It contains two methods:</p>
<ol>
<li><code>[didReceive(_:withContentHandler:)](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension/1648229-didreceive)</code> — make any needed changes to the notification and notify the system when you’re done. This method has a limited amount of time (about 30 secs) to perform its task and execute the provided completion block.</li>
<li><code>[serviceExtensionTimeWillExpire()](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension/1648227-serviceextensiontimewillexpire)</code> — Tells us that the extension is about to be terminated. Give us one last chance to submit our changes. If we don’t update the notification content before time expires, the system displays the original content.</li>
</ol>
<p>Let’s look at an example. We’ll change the <strong>body</strong> in <strong>payload</strong> in <strong>Code Snippet 7</strong> to “<em>Address: Sea Shells Apartments, Mumbai</em>”.</p>
<p>All the default implementation of both the methods is provided by the extension itself. We just have to make the changes we want, like in Line 8 in the above code snippet. Just a single line of code for now. Similarly, you can modify other fields as per your requirements.</p>
<h3 id="heading-notification-content-extension">Notification Content Extension</h3>
<p>Having an eye-catching UI is always better than a simple default UI. Adding some colors and some pretty fonts is never a bad idea. We’re going to do the same with our notifications to make them look Wow!?</p>
<p>And and and…<strong>Apple</strong> is here to our rescue again. <strong>Notification content extension</strong> it is. This presents a custom interface for a delivered <strong>local</strong> <strong>or</strong> <strong>remote</strong> notification.</p>
<h4 id="heading-adding-notification-content-extension-to-the-project">Adding Notification Content Extension to the project</h4>
<p>I think we already know how to do that. Don’t we? We’re going to the same what we did for adding <strong>Notification Service Extension</strong>. Select <strong>File</strong> — <strong>New</strong> — <strong>Target</strong> — <strong>Notification Content Extension.</strong></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*5QBuMXXIn9e896Bg0Az2Iw.png" alt="Image" width="800" height="573" loading="lazy"></p>
<h4 id="heading-adding-some-keys-to-extensions-infoplist">Adding some keys to extension’s Info.plist</h4>
<p>To support custom UI for local and remote notifications, we need to make some changes in the <strong>Info.plist</strong> file of content extension.</p>
<ol>
<li><strong>UNNotificationExtensionCategory (reqd.)</strong> <em>—</em> A string or an array of strings. Each string contains the identifier of a category declared by the app. <strong>Category</strong>, I must say, is really really important for notifications. Custom UI will only appear for the notifications lying in the specified categories.</li>
<li><strong>UNNotificationExtensionInitialContentSizeRatio (reqd.)</strong> <em>—</em> A floating-point number that represents the initial size of the view controller’s view expressed as a <strong>ratio of its height to its width</strong>. It’s the view controller that we’ll use for making custom UI. We’ll discuss that in the upcoming section.</li>
<li><strong>UNNotificationExtensionDefaultContentHidden — if true</strong>: show only custom content. <strong>If</strong> <strong>false</strong>: show custom+default content.</li>
<li><strong>UNNotificationExtensionOverridesDefaultTitle —if true</strong>: set the notification’s title to the title of the view controller. <strong>If false</strong>: notification’s title is set to app’s name.</li>
</ol>
<p>Here is an illustration that can help us understand the above keys better.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*SiSHq4lvgJA58h4N9DToIA.png" alt="Image" width="704" height="442" loading="lazy"></p>
<p>In the above illustration, the keys in <strong>Info.plist</strong> are configured as:</p>
<ol>
<li><strong>UNNotificationExtensionCategory</strong> <em>—</em> INVITATION</li>
<li><strong>UNNotificationExtensionInitialContentSizeRatio</strong> <em>—</em> 1</li>
<li><strong>UNNotificationExtensionDefaultContentHidden</strong> <em>—</em> false</li>
<li><strong>UNNotificationExtensionOverridesDefaultTitle</strong> <em>—</em> false</li>
</ol>
<h4 id="heading-creating-the-custom-ui">Creating the custom UI</h4>
<p>Notification content extension provides us with a <code>UIViewController</code> that conforms to <code>[UNNotificationContentExtension](https://developer.apple.com/documentation/usernotificationsui/unnotificationcontentextension)</code> protocol. This controller presents the interface of the notification. The <code>Storyboard</code> file in the extension contains a single ViewController that we can use to create whatever UI we want the notification to present.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*TjlQ9z2HaTKIzx-M5ISJSg.png" alt="Image" width="800" height="415" loading="lazy"></p>
<p>Once we create the UI, we need to connect the elements in the <code>NotificationViewController</code> in order to fill in the details. Whenever a notification arrives with an expected <strong>category</strong>, we receive a callback in <code>UNNotificationContentExtension’s</code> method — <code>[didReceive(_:)](https://developer.apple.com/documentation/usernotificationsui/unnotificationcontentextension/1648525-didreceive)</code> . This is the place where we can add details to our customized UI.</p>
<p>We’re almost done with our notification’s custom UI. Just 1 more thing. Since the custom UI is attached to the notifications’ <strong>category,</strong> that may have some actions attached to it. And…you got that right! ?We’ll get our actions automatically without any custom handling. Brilliant!?</p>
<p><strong>Content + Beautiful UI + Custom Actions</strong> — Everything done. What more can we ask for? Apple, you are great!?</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*q8FG_H9ZcnMbg_SiGySsFQ.png" alt="Image" width="500" height="889" loading="lazy"></p>
<p>One last point: we can add handling to the custom actions in the extension, too. The system calls <code>[didReceive(_:completionHandler:)](https://developer.apple.com/documentation/usernotificationsui/unnotificationcontentextension/1845197-didreceive)</code> method to respond to any selected actions. If our view controller doesn’t implement that method, the system delivers the selected action to your app for handling.</p>
<p>If implemented, we need to handle all the possible actions in this method. One thing that is important here is the <code>completion</code> closure.</p>
<p><code>completion</code>: The block to execute when you are finished performing the action. You must call this block at some point during your implementation. The block has no return value.</p>
<p>The closure accepts a single parameter <code>dismiss</code> of type <code>[UNNotificationContentExtensionResponseOption](https://developer.apple.com/documentation/usernotificationsui/unnotificationcontentextensionresponseoption)</code> . We provide the following options:</p>
<ol>
<li><code>doNotDismiss</code> — Don’t dismiss the notification interface.</li>
<li><code>dismiss</code> — Dismiss the notification interface.</li>
<li><code>dismissAndForwardAction--</code>Dismiss the notification interface and forward the notification to the app.</li>
</ol>
<p>That sums up our notifications. Too much to remember? <strong>Practise makes Progress</strong> ?. Try making your own notifications now!</p>
<h3 id="heading-sample-project">Sample Project</h3>
<p>You can download the sample project from <a target="_blank" href="https://github.com/pgpt10/Notifications">here</a>.</p>
<p>And the sample project for <strong>Notification Content Extension</strong> can be found <a target="_blank" href="https://github.com/pgpt10/RichNotificationSample">here</a>.</p>
<h3 id="heading-further-reading">Further reading</h3>
<p>Don’t forget to read my other articles:</p>
<ol>
<li><a target="_blank" href="https://hackernoon.com/everything-about-codable-in-swift-4-97d0e18a2999">Everything about Codable in Swift 4</a></li>
<li><a target="_blank" href="https://hackernoon.com/color-it-with-gradients-ios-a4b374c3c79f">Color it with GRADIENTS — iOS</a></li>
<li><a target="_blank" href="https://hackernoon.com/drag-it-drop-it-in-collection-table-ios-11-6bd28795b313">Coding for iOS 11: How to drag &amp; drop into collections &amp; tables</a></li>
<li><a target="_blank" href="https://hackernoon.com/app-extensions-and-today-extensions-widget-in-ios-10-e2d9fd9957a8">All you need to know about Today Extensions (Widget) in iOS 10</a></li>
<li><a target="_blank" href="https://hackernoon.com/uicollectionviewcell-selection-made-easy-41dae148379d">UICollectionViewCell selection made easy..!!</a></li>
</ol>
<p>Feel free to leave comments in case you have any questions.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to make an App Store-worthy iOS app preview on a budget ]]>
                </title>
                <description>
                    <![CDATA[ By Jake Shelley Back in 2014, Apple made it possible to add an app preview to the the App Store. App previews are the best way to show potential users what your app has to offer before they download the app. In fact, users are 3x more likely to insta... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-make-an-app-store-worthy-ios-app-preview-on-a-budget-c4a7de1d5401/</link>
                <guid isPermaLink="false">66d45f33230dff016690580f</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sat, 31 Mar 2018 07:56:38 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*BkBLvnsaD7NaXFVj3quLGQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jake Shelley</p>
<p>Back in 2014, Apple made it possible to add an app preview to the the App Store. App previews are the best way to show potential users what your app has to offer before they download the app. In fact, users are 3x more likely to install an app with an app preview, according to <a target="_blank" href="https://www.storemaven.com/">StoreMaven</a>.</p>
<p>Unfortunately, many solo makers don’t have the budget to hire a professional to make an app preview. Recently, I found myself in this position, and after some digging, I found a couple of free tools to make a quality app preview.</p>
<p>In this post, I’m going to go over the following:</p>
<ol>
<li>Preparing the content</li>
<li>Recording the video</li>
<li>Editing the video</li>
<li>Common issues</li>
</ol>
<p>I’m assuming that you are using a Mac, which comes with Xcode, Quicktime, and iMovie for free. If you are not using a Mac you might need to purchase these tools.</p>
<h4 id="heading-preparing-the-content">Preparing the content</h4>
<p>Each app developer knows the most engaging and fun parts of their app. Make sure to highlight those in your app preview. Figure out where you need to add text overlays and ensure the text contrasts with the background it’s displayed on.</p>
<p>As of iOS 11, you can have up to three app previews to show off your app. It may be tempting to use the entire 90 seconds you are given, but I would suggest loading your most interesting features in the first one. If users aren’t interested in your app by the first preview, it’s unlikely they’ll take the time to watch the other two.</p>
<p>Finally, you may want to show the users how they will interact with your app. To show off touches and gestures, use <a target="_blank" href="https://github.com/LukasCZ/GSTouchesShowingWindow-Swift">GSTouchesShowingWindow</a>. It’s super easy to install and will show off how users will interact with your app.</p>
<h4 id="heading-recording-the-video">Recording the video</h4>
<p>Once you have decided the content you want to show, you can start recording your video. The easiest way to do this is to use <strong>Quicktime</strong> to record the screen of a connected iPhone.</p>
<p>Plugin your iPhone, then open quicktime and hit <code>File &gt; New Movie Record</code>ing. This will open a recording window. From the dropdown next to the record button, you can select the device you have connected.</p>
<p>Using a connected device means that you are limited only to the devices you have. Luckily, you can use <strong>Xcode CLI</strong> to record your simulator actions.</p>
<p>To record with the Xcode CLI, begin running your simulator in Xcode. Then, open your terminal and enter the following command:</p>
<pre><code>$ xcrun simctl io booted recordVideo example.mp4
</code></pre><p>Perform the actions you want to record in the simulator then <code>ctr-C</code> in your terminal to end the recording session. The above command will add the video <code>example.mp4</code> to the current directory of your terminal.</p>
<h4 id="heading-editing-the-video">Editing the Video</h4>
<p>There are two goals you are trying to hit while editing your preview:</p>
<ol>
<li>Show your app in the best light possible</li>
<li>Edit the preview down to between 15 and 30 seconds</li>
</ol>
<p>The best tool for editing an app preview is <strong>iMovie</strong>. Open iMovie and click <code>File &gt; New App Prev</code>iew. Drop your video into the media area to add it to your project.</p>
<p>I’m not going to go into details of how to edit an iMovie app, but the UI is pretty intuitive. Just drag and drop the scenes you want onto the lower area to add them to your clip. <code>command+B</code> will allow you to split your clip so you can fit cool transitions and keep track of the pacing better. You can add transitions between split clips, audio, and title screens.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/OR3RzAsbdE1jvl6TmgArn3wRGgzwkkelV1ME" alt="Image" width="800" height="580" loading="lazy">
<em>You can add text overlays and audio to your app preview in iMovie before exporting it</em></p>
<p>Once you are done editing, click <code>File &gt; Share &gt; App P</code>review (if you don’<code>t see App P</code>review you can also <code>clic</code>k file). Then, select the destination you want to save it to and hit enter. After a few seconds, your video will be available.</p>
<h4 id="heading-common-issues">Common issues</h4>
<p>So at this point there is a good chance you already have everything ready to go, but when you try to upload your preview to iTunes Connect, you get an error. It is likely that your problems are caused by one of these two app preview requirements:</p>
<ol>
<li>Your app preview’s resolution must match the requirements for the device type</li>
<li>Your app preview must run at 30 fps</li>
</ol>
<p>The likelihood that your app preview’s resolution doesn’t meet the requirements is pretty low, but I actually ran into trouble <strong>even when I recorded directly from my iPhone</strong><em>.</em> For whatever reason, Quicktime captured everything off by one pixel, so iTunes Connect refused to let me upload the video.</p>
<p>After some searching, I found a free tool that lets you crop your <code>.mov</code> (or any video type) into the correct resolution. Go to <a target="_blank" href="https://ezgif.com/">ezgif.com</a> and click <code>Video to GIF</code> on the nav bar. This opens another nav bar below the first one, where you will see <code>Crop video</code>. Click that, then you can upload your quicktime <code>.mov</code> file. Crop the video to the size you need and download the new file.</p>
<p>If you face issues related to your app preview not running at 30 fps, that’s an easy one to fix (for free) with <a target="_blank" href="https://www.ffmpeg.org/">ffmpeg</a>. Open your terminal, ensure you have <a target="_blank" href="https://brew.sh/">homebrew</a> installed, and enter:</p>
<pre><code>$ brew install ffmpeg
</code></pre><p>Now with ffmpeg installed, <code>cd</code> into the directory that contains your video and enter:</p>
<pre><code>$ ffmpeg -i <span class="hljs-string">"original.mov"</span> -r <span class="hljs-number">30</span> <span class="hljs-string">"converted_30fps_video.mov"</span>
</code></pre><p>This will output your video converted to 30 fps.</p>
<h4 id="heading-conclusion">Conclusion</h4>
<p>You should now have an app preview that meets all of Apple’s requirements. Having an app preview is important so that your app stands out from the millions of apps on the app store. I found that the tools used in this guide landed me with a high quality app preview that I felt marketed my app well, and it didn’t cost a dime!</p>
<p>I hope this guide saved you some time and money. Good luck on the app store!</p>
<p><em>Thanks so much for reading! If you liked this story, follow me on <a target="_blank" href="https://twitter.com/JakeShelley3">Twitter</a> where I post articles about product management, engineering, and design.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Your ultimate guide to the Google Maps SDK on iOS, using Swift 4 ]]>
                </title>
                <description>
                    <![CDATA[ By Dejan Atanasov Many iOS apps use Google Maps. This is a very common feature, so I have decided to prepare an ultimate guide on the Google Maps SDK for iOS. This tutorial covers everything that you might need to know. I hope that my readers will re... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-you-can-use-the-google-maps-sdk-with-ios-using-swift-4-a9bba26d9c4d/</link>
                <guid isPermaLink="false">66c356e17ef110ecbf367afd</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ios app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 26 Oct 2017 03:16:01 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*0ONsJHjgFTW1SF_amzDM6g.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dejan Atanasov</p>
<p>Many iOS apps use Google Maps. This is a very common feature, so I have decided to prepare an ultimate guide on the Google Maps SDK for iOS. This tutorial covers everything that you might need to know.</p>
<p>I hope that my readers will request features, so I can expand this article. Everything will be documented in this post! ?</p>
<h3 id="heading-installation">Installation</h3>
<p>Before we start coding, we must install the Google Maps iOS SDK first. You might prefer some other dependency manager, but I would recommend <a target="_blank" href="https://cocoapods.org/">CocoaPods</a>.</p>
<p>Create a Podfile inside your project root directory, and copy the following code:</p>
<pre><code>source <span class="hljs-string">'https://github.com/CocoaPods/Specs.git'</span>target <span class="hljs-string">'YOUR_TARGET_NAME'</span> <span class="hljs-keyword">do</span>  pod <span class="hljs-string">'GoogleMaps'</span>end
</code></pre><p>All you need to do is changing the YOUR_TARGET_NAME string with a real value. Save the file and close it. Open the terminal and cd to the root directory of the project, then type <code>pod install</code>. You're done! ?</p>
<h3 id="heading-get-an-api-key">Get an API key</h3>
<p>To use the Google Maps iOS SDK, you will need an API Key. To generate the key you will need to visit the <a target="_blank" href="https://console.developers.google.com/flows/enableapi?apiid=maps_ios_backend&amp;reusekey=true">Google API Console</a>.<br>Create a project, and navigate to ‘Credentials’.</p>
<p>Then, click ‘Generate Credentials’ and pick API Key. You will need to provide your projects bundle id. The key is generated by the unique bundle id, so if it’s changed, the Google Maps services <strong>won’t work</strong>!</p>
<p>Go to your project, and in your <code>AppDelegate.swift</code> class add <code>import GoogleMaps</code>. Then, copy the following code to <code>application(_:didFinishLaunchingWithOptions:)</code></p>
<pre><code>GMSServices.provideAPIKey(<span class="hljs-string">"YOUR_API_KEY"</span>)
</code></pre><h3 id="heading-step-1-add-a-map"><code>Step 1 — Add a map</code></h3>
<p>I will start by showing you how to set up the map together with a basic marker. The code that you will see here is tested in parallel as I write.</p>
<p>Let’s start! ?</p>
<p>Visit your UIViewController (where you need to add the map). Create a custom UIView with the size you need. Assign the <code>GMSMapView</code> class as a <strong>Custom Class</strong> to the UIView (see the screenshot below). Also, don't forget to connect the delegate.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*zb3cuSmzcs1byI9_wNw6rA.png" alt="Image" width="500" height="353" loading="lazy"></p>
<h4 id="heading-finally-some-code">Finally, some code!</h4>
<p>Let’s get back to the UIViewController and write some code. ⌨️<br>️In the below snippet, I have added the whole class so you can get a better picture of what is going on.</p>
<p><code>GMSCameraPosition</code> tells the map which coordinates to take as a center point. To show a simple marker on the map, use the <code>showMarker()</code> function.</p>
<p>At the end of the file, add an <a target="_blank" href="http://theappspace.com/i-%E2%9D%A4-swift-part-1-organize-uiviewcontroller-classes-by-using-extensions/">extension</a> which will “store” the <code>GMSMapViewDelegate</code> methods that we need.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*PljEkFaSEt10AzemQsFlzg.png" alt="Image" width="300" height="533" loading="lazy"></p>
<h3 id="heading-step-2-delegate-methods">Step 2 — Delegate methods</h3>
<p>I will now introduce you to some <code>GMSMapViewDelegate</code> methods and their powers. ✊</p>
<h4 id="heading-gmsmarker-infowindow">GMSMarker InfoWindow</h4>
<p>In Google Maps, an InfoWindow is a popup window with extra information about a given location. It is displayed when the user taps on the marker we added above.</p>
<p>Our InfoWindow is customizable. You can attach your own UIView with whatever components you need.</p>
<p>I have written an example implementation. This assumes in most cases people will use a custom InfoWindow,</p>
<ul>
<li><code>didTapInfoWindowOf()</code> detects when the user taps on the InfoWindow.</li>
<li><code>markerInfoWindow()</code> adds the custom UIView that we want to show to the marker.</li>
<li><code>didLongPressInfoWindowOf()</code> detects when the InfoWindow has been long pressed.</li>
</ul>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*B1__Cl82zpZ2U4QJ0RsMkw.png" alt="Image" width="400" height="344" loading="lazy"></p>
<h4 id="heading-drag-gmsmarker">Drag GMSMarker</h4>
<p>Another interesting feature in GMSMapViewDelegate is the ability to drag the marker. This can be achieved with a minimal amount of code.</p>
<p>All you have to do is turn on the “switch”, by calling <code>marker.isDragabble=true</code>on the marker created above.</p>
<p>In order to drag the marker, you will need to use a long press. If you need to be notified when the user starts and ends dragging, you can implement these three delegate methods:</p>
<ul>
<li><code>didBeginDragging</code> notifies once — when the dragging has started.</li>
<li><code>didDrag</code> notifies while the marker is being dragged.</li>
<li><code>didEndDragging</code> notifies once — when the dragging has ended.</li>
</ul>
<h4 id="heading-gmsmarker-position">GMSMarker position</h4>
<p>What if you need to change the <code>GMSMarker</code> position while the user is tapping on the map? Well, <code>GMSMapViewDelegate</code> offers a solution for that as well. A single delegate method can intercept the coordinates (latitude and longitude) of the tapped area. It will then assign their values to the marker.</p>
<ul>
<li><code>didTapAt()</code> returns the coordinate from the tapped area on the map</li>
</ul>
<h3 id="heading-step-3-adding-shapes">Step 3 — Adding shapes</h3>
<p>The Google Maps iOS SDK makes it simple to draw a shape. I will cover how to draw with polylines, polygons and circles.</p>
<h4 id="heading-polylines">Polylines</h4>
<p>Shapes can be built using lines. We can draw lines in Google Maps using ‘polylines’. The object that will help us with the drawing is called <code>GMSPolyline</code>.</p>
<p>To create a polyline, you will need to create a path using <code>GMSMutablePath</code>. It needs two or more points to start creating a path.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*8QR6Xcs9Z9kG2L50hWMBsw.png" alt="Image" width="400" height="248" loading="lazy"></p>
<p>If you have used the above example, you will get a rectangular shape like the one shown.</p>
<p><strong>Some other useful tips:</strong></p>
<ul>
<li>To remove a polyline from the map, call <code>mapView.clear()</code>.</li>
<li>You can change the color of the line by using <code>polyline.strokeColor=.black</code>.</li>
<li>Change the width of the line by calling <code>polyline.strokeWidth=3</code>.</li>
</ul>
<h4 id="heading-polygon">Polygon</h4>
<p>Polygon is almost the same as polylines. It works using the same approach, with a few minor differences.</p>
<p>For example, <code>GMSPolygon</code>will draw a shape. You can then use <code>fillColor</code> to fill in the drawn area. Here is an example of what this looks like.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*79iM1lo6ICzmy5DmJM43kA.png" alt="Image" width="400" height="200" loading="lazy"></p>
<h4 id="heading-radius-circle">Radius (circle)</h4>
<p>The final shape we will look at is a circle. This is probably the easiest shape of all, since it’s always the same!</p>
<p>To achieve this, we need to use the<code>GMSCircle</code> class. Here, we are not passing a path. Instead, we use one coordinate to specify the circle’s center. We also define a radius (measured in meters).</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*l41eb5zRtfO-1QWiYlKBWw.png" alt="Image" width="299" height="141" loading="lazy"></p>
<p>The<code>GMSCircle</code> class contains the same properties as the polygon, including<code>fillColor</code> , <code>strokeColor</code> and <code>strokeWidth</code>.</p>
<h3 id="heading-step-4-properties-and-settings">Step 4 — Properties and Settings</h3>
<p>This part will cover a few properties and settings that are often used when using Google Maps in your app. Let’s take a look at them.</p>
<h4 id="heading-change-marker-icon">Change marker icon</h4>
<p>The <code>GMSMarker</code>contains two different properties for changing the marker icon.</p>
<ul>
<li><code>marker.icon=UIImage(named: "image.png")</code> in this approach, you pass an image filename. This replaces the default one.</li>
<li><code>marker.iconView=customView</code> You can also add a custom view instead of an image. This can be used for more complex markers. For example, you may want to add some animation, or multiple components (instead of a single image). Note the <code>icon</code> property gets overwritten when <code>iconView</code> is called.</li>
</ul>
<h4 id="heading-add-my-location-button">Add ‘My Location’ button</h4>
<p>The ‘My Location’ button appears in the bottom right corner. Clicking the button will animate the map to show the user’s current location.</p>
<p>To add this, set <code>mapView.settings.myLocationButton = true</code>. The button will appear.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*EgK9Q4dvn3-IuGOvOvvOtw.png" alt="Image" width="300" height="70" loading="lazy"></p>
<h4 id="heading-zoom-controls">Zoom controls</h4>
<p>Google Maps SDK for iOS doesn’t provide inbuilt zoom controls (but the Android SDK does). You will need to write your own logic instead.</p>
<p>All you need to do is add two buttons with ‘+’ and ‘-’ icons. When tapped, these will call <code>mapView.animate(toZoom: zoom)</code>.</p>
<h4 id="heading-control-gestures">Control gestures</h4>
<p>You can turn on or off any gesture that you can see on the map. For example, you might want to disable zooming, or turn off scrolling.</p>
<p>There are a total of four gestures available to you:</p>
<pre><code>mapView.settings.scrollGestures = falsemapView.settings.zoomGestures   = falsemapView.settings.tiltGestures   = falsemapView.settings.rotateGestures = <span class="hljs-literal">false</span>
</code></pre><p>I hope that you have enjoyed this tutorial. If you want to read more on Google Maps SDK for iOS, write me a comment. I would be very happy to expand this tutorial with your requests.</p>
<h4 id="heading-thats-it-from-this-tutorial-and-if-it-helped-you-please-or-share-this-story-so-others-like-you-can-find-it-thank-you-for-your-attention">That’s it from this tutorial and if it helped you please ? or share this story so others like you can find it. Thank you for your attention! ?</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*5-oC2BqqizoRxIls08WMmA.png" alt="Image" width="800" height="320" loading="lazy"></p>
<h4 id="heading-check-out-my-latest-project">Check out my latest project:</h4>
<p><a target="_blank" href="https://apple.co/2EIiDpI"><strong>‎1x2 BET - Soccer Tips &amp; Odds</strong></a><br><a target="_blank" href="https://apple.co/2EIiDpI">_‎HOT ODDS Each day, we generate a list of the hottest odds in the world. These are odds that have dropped the most…_apple.co</a></p>
<h4 id="heading-read-more-of-my-writing-on-medium">Read more of my writing on Medium:</h4>
<p><a target="_blank" href="https://hackernoon.com/introducing-clean-swift-architecture-vip-770a639ad7bf"><strong>Introducing Clean Swift Architecture (VIP)</strong></a><br><a target="_blank" href="https://hackernoon.com/introducing-clean-swift-architecture-vip-770a639ad7bf">_Forget MVC, now!_hackernoon.com</a><a target="_blank" href="https://medium.freecodecamp.org/how-you-can-use-the-google-maps-sdk-with-ios-using-swift-4-a9bba26d9c4d"><strong>Your ultimate guide to the Google Maps SDK on iOS, using Swift 4</strong></a><br><a target="_blank" href="https://medium.freecodecamp.org/how-you-can-use-the-google-maps-sdk-with-ios-using-swift-4-a9bba26d9c4d">_Many iOS apps use Google Maps. This is a very common feature, so I have decided to prepare an ultimate guide on the…_medium.freecodecamp.org</a><a target="_blank" href="https://medium.com/theappspace/swift-custom-uiview-with-xib-file-211bb8bbd6eb"><strong>SWIFT — Custom UIView with XIB file</strong></a><br><a target="_blank" href="https://medium.com/theappspace/swift-custom-uiview-with-xib-file-211bb8bbd6eb">_Custom UIView with XIB file is a very common practice in iOS Development. Custom UIView classes don’t contain XIB files…_medium.com</a><a target="_blank" href="https://hackernoon.com/how-to-add-spotlight-support-to-your-ios-app-4a89054aff89"><strong>How to add Spotlight support to your iOS app</strong></a><br><a target="_blank" href="https://hackernoon.com/how-to-add-spotlight-support-to-your-ios-app-4a89054aff89">_A Swift tutorial that will make your app available in Spotlight search_hackernoon.com</a><a target="_blank" href="https://hackernoon.com/core-data-relationships-d813ed66ba8c"><strong>Core Data Relationships</strong></a><br><a target="_blank" href="https://hackernoon.com/core-data-relationships-d813ed66ba8c">_Understanding One-to-One and One-To-Many relationships_hackernoon.com</a><a target="_blank" href="https://hackernoon.com/understanding-auto-layout-in-xcode-9-2719710f0706"><strong>Understanding Auto Layout in Xcode 9</strong></a><br><a target="_blank" href="https://hackernoon.com/understanding-auto-layout-in-xcode-9-2719710f0706">_All you need to know about Auto Layout_hackernoon.com</a></p>
<h4 id="heading-subscribe-to-my-newsletter">Subscribe to my Newsletter:</h4>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
