<?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[ Xcode - 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[ Xcode - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:31:01 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/xcode/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <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 Install Xcode Command Line Tools on a Mac ]]>
                </title>
                <description>
                    <![CDATA[ Developers need to install Xcode Command Line Tools before they can develop software on a Mac. Apple provides a complete development environment for programmers named Xcode. If you are developing software for macOS, iOS, tvOS, and watchOS, you must i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/install-xcode-command-line-tools/</link>
                <guid isPermaLink="false">66ba1609a16d07b8deb68309</guid>
                
                    <category>
                        <![CDATA[ Apple ]]>
                    </category>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ macOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Xcode ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Kehoe ]]>
                </dc:creator>
                <pubDate>Mon, 19 Jul 2021 22:25:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/07/Terminal_Mac.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Developers need to install Xcode Command Line Tools before they can develop software on a Mac.</p>
<p>Apple provides a complete development environment for programmers named Xcode. If you are developing software for macOS, iOS, tvOS, and watchOS, you must install the full Xcode application. </p>
<p>It's not pre-installed, but you can install it from the <a target="_blank" href="https://developer.apple.com/download/">Apple developer website</a> or the App Store on your Mac.</p>
<h2 id="heading-what-are-xcode-command-line-tools">What are Xcode Command Line Tools?</h2>
<p>If you're not developing software for an Apple device, you won't need the full Xcode application (it requires over 40GB of disk space!).</p>
<p>Instead, you'll install Xcode Command Line Tools. It's a smaller package for software developers with tools that run on the command line, that is, in the Terminal application.</p>
<p>Programmers have used these tools on Unix operating systems since computing's beginnings, and they serve as the foundation of almost all software development. </p>
<p>Luckily, the Xcode Command Line Tools package only requires 1.2GB of space on your disk.</p>
<p>You have three choices to install Xcode Command Line Tools on a Mac:</p>
<ul>
<li>install the full Xcode package</li>
<li>install Xcode Command Line Tools when triggered by a command</li>
<li>install Xcode Command Line Tools as part of a Homebrew installation.</li>
</ul>
<p>I don't recommend installing the full Xcode package unless you're developing software for an Apple device. The download will take too long and it will consume unnecessary disk space. Instead, try either of two faster methods.</p>
<h2 id="heading-how-to-install-xcode-command-line-tools-from-a-command-prompt">How to Install Xcode Command Line Tools from a Command Prompt</h2>
<p>Apple has made it easy to install Xcode Command Line Tools because certain commands will prompt you to begin installation.</p>
<p>Here are examples of commands that will trigger a prompt to install Xcode Command Line Tools:</p>
<ul>
<li><code>clang</code> – a compiler that turns source code into an executable program</li>
<li><code>gcc</code> – the GNU compiler</li>
<li><code>git</code> – the save-as-you-go version control system</li>
</ul>
<p>Running any of these commands in the terminal will bring up a prompt to install Xcode Command Line Tools. I've written elsewhere about <a target="_blank" href="https://mac.install.guide/terminal/index.html">How to Open Terminal on MacOS</a> – just click the Spotlight icon in the menu bar and type “terminal.”</p>
<p>You can also enter the command <code>xcode-select --install</code> in the terminal to begin the installation process. You'll see a panel that asks you to install Xcode Command Line Tools.</p>
<p><img src="https://mac.install.guide/assets/images/ruby/install-Xcode-CLT.png" alt="Image" width="573" height="307" loading="lazy"></p>
<p>Click 'Install' to begin the download and installation process.</p>
<p><img src="https://mac.install.guide/assets/images/ruby/install-Xcode-CLT-progress.png" alt="Image" width="566" height="230" loading="lazy"></p>
<p>Installation takes 8 minutes on a 2021 Mac M1 Mini, with a 100Mbps Internet connection. It's significantly slower on Mac Intel over a slow Internet connection.</p>
<p><img src="https://mac.install.guide/assets/images/ruby/install-Xcode-CLT-done.png" alt="Image" width="566" height="200" loading="lazy"></p>
<p>You'll see a confirmation message when installation is complete.</p>
<p>Verify that you've successfully installed Xcode Command Line Tools:</p>
<pre><code class="lang-bash">$ xcode-select -p
</code></pre>
<p>You should see the following:</p>
<pre><code class="lang-bash">/Library/Developer/CommandLineTools
</code></pre>
<h2 id="heading-how-to-use-homebrew-to-install-xcode-command-line-tools">How to Use Homebrew to Install Xcode Command Line Tools</h2>
<p>As easy as it is to use the command prompt to install Xcode Command Line Tools, I recommend an even easier method: using Homebrew.</p>
<p>This option was only recently added to Homebrew, so many developers are not aware of it.</p>
<p>Homebrew is the popular Mac package manager. Most developers need programming languages and utilities that don't come installed on macOS and are not included in the Xcode Command Line Tools package. Homebrew can install almost any open-source tool for developers.</p>
<p>Since you'll probably need Homebrew, you might as well let Homebrew install Xcode Command Line Tools for you.</p>
<p>First, check if Homebrew is already installed.</p>
<pre><code class="lang-bash">$ brew
</code></pre>
<p>If Homebrew is not installed, you will see:</p>
<pre><code class="lang-bash">zsh: <span class="hljs-built_in">command</span> not found: brew
</code></pre>
<p>Homebrew provides an installation script you can run with a single command (check that it hasn't changed at the <a target="_blank" href="https://brew.sh/">Homebrew site</a>).</p>
<pre><code class="lang-bash">$ /bin/bash -c <span class="hljs-string">"<span class="hljs-subst">$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)</span>"</span>
</code></pre>
<p>The Homebrew installation script will ask you to enter your Mac user password. This is the password you use to sign in to your Mac.</p>
<pre><code class="lang-bash">Password:
</code></pre>
<p>You won't see the characters as you type. Press enter when you are done.</p>
<p><img src="https://mac.install.guide/assets/images/ruby/homebrew-enter-password.png" alt="Image" width="697" height="245" loading="lazy"></p>
<p>If you haven't already installed Xcode Command Line Tools, you'll see a message that "The Xcode Command Line Tools will be installed." Press return to continue when prompted by the Homebrew installation script.</p>
<p><img src="https://mac.install.guide/assets/images/ruby/install-homebrew.png" alt="Image" width="697" height="525" loading="lazy"></p>
<p>You’ll see diagnostic and progress messages. Homebrew installation takes 2 to 15 minutes on a 2021 Mac M1 Mini, with a 100Mbps Internet connection. It's significantly slower on Mac Intel over a slow Internet connection.</p>
<p><img src="https://mac.install.guide/assets/images/ruby/homebrew-complete.png" alt="Image" width="653" height="355" loading="lazy"></p>
<p>On Mac Intel machines, that's all you need to do – Homebrew is ready to use. On Mac Intel, Homebrew installs itself into the <code>/usr/local/bin</code> directory, which is already configured for access by the shell with the macOS default <code>$PATH</code>.</p>
<p>On Apple Silicon machines, there's one more step. Homebrew files are installed into the <code>/opt/homebrew</code> folder. But the folder is not part of the default <code>$PATH</code>. Follow Homebrew's advice and create a <code>~/.zprofile</code> file that contains a command which sets up Homebrew. Homebrew shows instructions at the end of the installation process:</p>
<pre><code class="lang-bash">- Add Homebrew to your PATH <span class="hljs-keyword">in</span> ~/.zprofile:
<span class="hljs-built_in">echo</span> <span class="hljs-string">'eval "$(/opt/homebrew/bin/brew shellenv)"'</span> &gt;&gt; ~/.zprofile
<span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(/opt/homebrew/bin/brew shellenv)</span>"</span>
</code></pre>
<p>After you've installed Homebrew, check that Homebrew is installed properly.</p>
<pre><code class="lang-bash">$ brew doctor
</code></pre>
<p>You should see this:</p>
<pre><code class="lang-bash">Your system is ready to brew.
</code></pre>
<p>If Homebrew is successfully installed, there will be Homebrew files in <code>/usr/local</code> (for macOS Intel) or <code>/opt/homebrew</code> (for Apple Silicon).</p>
<p>Now you have both Xcode Command Line Tools and Homebrew installed. If you want to learn more about adding Homebrew packages to set up your development environment, see <a target="_blank" href="https://mac.install.guide/homebrew/6.html">Install a Homebrew Package</a>.</p>
<h2 id="heading-more-information">More information</h2>
<p>I've written an in-depth guide to <a target="_blank" href="https://mac.install.guide/commandlinetools/index.html">Install Xcode Command Line Tools</a> that goes beyond these basics. </p>
<p>In the guide, I explain how to check if <a target="_blank" href="https://mac.install.guide/commandlinetools/2.html">Xcode Command Line Tools Are Already Installed</a>. I go into more detail about how to <a target="_blank" href="https://mac.install.guide/commandlinetools/3.html">Install Xcode Command Line Tools with Homebrew</a>. Finally, I explain how to <a target="_blank" href="https://mac.install.guide/commandlinetools/6.html">Uninstall Xcode Command Line Tools</a>, <a target="_blank" href="https://mac.install.guide/commandlinetools/7.html">Reinstall Xcode Command Line Tools</a>, and provide a <a target="_blank" href="https://mac.install.guide/commandlinetools/8.html">List of Xcode Command Line Tools</a> that you can use.</p>
<p>There's also a complete guide to <a target="_blank" href="https://mac.install.guide/homebrew/index.html">Install Homebrew for Mac</a> that explains how to <a target="_blank" href="https://mac.install.guide/homebrew/4.html">Update Homebrew</a>, <a target="_blank" href="https://mac.install.guide/homebrew/5.html">Uninstall Homebrew</a>, and keep up with other <a target="_blank" href="https://mac.install.guide/homebrew/8.html">Housekeeping for Homebrew</a>.</p>
<h2 id="heading-your-development-environment">Your development environment</h2>
<p>MacOS is the most popular platform for software development because the operating system is based on Unix, the longtime standard for software development.</p>
<p>With Xcode Command Line Tools installed, you'll have a solid foundation for adding almost any open source development tool.</p>
<p>Add Homebrew and you have a package manager that can install version managers, programming languages, and almost any other tool you may need.</p>
<p>Combined with a text editor and terminal application, you'll be prepared for any tutorial you'll find on freeCodeCamp.</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 Upload Images To Xcode ]]>
                </title>
                <description>
                    <![CDATA[ By Ai-Lyn Tang To use images in Xcode, you need to upload them to Assets.xcassets, located in the Supporting Files folder. There are two options you can go with: bitmaps (aka .png files) or vectors (aka .pdf files). The first step is deciding which f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-upload-images-to-xcode/</link>
                <guid isPermaLink="false">66d45d60bd438296f45cd38b</guid>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Xcode ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 01 Sep 2019 06:54:16 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9ca08f740569d1a4ca4969.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ai-Lyn Tang</p>
<p>To use images in Xcode, you need to upload them to <code>Assets.xcassets</code>, located in the <code>Supporting Files</code> folder. There are two options you can go with: bitmaps (aka .<code>png</code> files) or vectors (aka <code>.pdf</code> files). The first step is deciding which file type you’d like to use.</p>
<h1 id="heading-the-difference-between-bitmaps-and-vector-assets">The difference between bitmaps and vector assets</h1>
<p>Most tutorials online use bitmap assets, which are <code>.png</code> files. This requires you to drag over 3 copies of the image into Xcode.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/1_PP9k-oGBon0-R_1XW3DHjg.png" alt="Image" width="600" height="400" loading="lazy">
<em>Drag and drop the three copies of your .png images here</em></p>
<p>However there is a school of thought that believes vector assets are superior. <a target="_blank" href="https://support.goanimate.com/hc/en-us/articles/203029524-Vector-vs-Bitmap-Images-How-to-Get-The-Best-Results-in-GoAnimate">This article</a> has a great explanation of why that’s the case. Vector assets are <code>.svg</code> files (or <code>.pdf</code> for Xcode). If you choose to use vectors assets, you only need to upload one version of the image to Xcode.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/1_05iKsfSZqTVZh8w3t8ZWFA.png" alt="Image" width="600" height="400" loading="lazy">
<em>Drag and drop your .pdf file here</em></p>
<p>Here’s what I’ve heard from those much wiser then I–Android phones use algorithms from the vector asset to generate the image in any size required. Makes sense given the wide breadth of devices and screen sizes for Android.</p>
<p>However vector assets in iPhones don’t actually scale with algorithms (apparently). So you don’t get higher quality images by using vectors over bitmaps. Instead what you get is the same quality as bitmap. The iPhone simply takes the “vector” asset and converts it to the same three bitmap sizes.</p>
<p>Aside from the algorithm logic above, there are a few more objective benefits of using vector assets for iPhones.</p>
<ol>
<li><strong>Reduces likelihood of human error.</strong> Right now there are three bitmap sizes (1x, 2x ,3x). That means you need to upload three images to your assets. That’s three opportunities to accidentally drag and drop the wrong image. When you use vector assets (which come up as universal in Xcode), you only need to upload one image instead of three. There’s less chance of uploading the incorrect size or image.</li>
<li><strong>Speed.</strong> Same reason as #1. If you are using a lot of images in your app, then using vector assets reduces the number of images you need to upload by a third.</li>
<li><strong>Future proofing.</strong> The iPhone currently only uses three image sizes (1x, 2x, 3x). This is to do with the increased retina quality of the screens. When Apple introduced the high retina screens a few years ago, the number of pixels per point increased for a sharper image.<br>It seems extremely likely that similar technological increases will continue to occur. In the future, we may need to upload 4x, 5x and 6x images. If we use a vector asset, the app will scale the image for us. This saves us from dropping in the new sizes of the bitmap asset.<br>Although I have to admit I’m a bit confused about this, given that iPhone vector assets don’t seem to actually work on algorithms. So I’m not sure how they will automatically scale to larger sizes. But my wise mentor explained this and I trust him!</li>
</ol>
<p>The one big downside for using vector assets in Xcode is that most places don’t provide the <code>.pdf</code> file. You need to convert it from <code>.svg</code> yourself.</p>
<p><em>Update on 18 June 2017</em>: Apple have announced in WWDC that iOS is now supporting true scalar images! Or at least, that’s what I think they announced. Now there is even more reason to use to use a single scale.</p>
<h1 id="heading-how-to-upload-a-vector-asset">How to upload a vector asset</h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/1_L-LclRKD3SRLmhnjbG1d2w.png" alt="Image" width="600" height="400" loading="lazy">
<em>Options to upload a vector asset</em></p>
<p>Head to the attributes menu. Change the scales to “single scale”, and check the resizing box to “preserve vector data”. This will change the upload option to “all” instead of 1x, 2x, 3x.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/1_05iKsfSZqTVZh8w3t8ZWFA-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Drag and drop your .pdf file here</em></p>
<p>Next you drag and drop your <code>.pdf</code> file into the one slot. I’m not too sure how to convert <code>.svg</code> to <code>.pdf</code> yet, but I assume it’s fairly easy with Preview.</p>
<h1 id="heading-how-to-upload-png-files">How to upload .png files</h1>
<p>If you decide to go ahead with <code>.png</code>, you’ll need to upload three versions of your file. This is to cover the varying screen resolutions of the different iPhones.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/1_GnT-kK2SC9E42YsI2k13EQ.png" alt="Image" width="600" height="400" loading="lazy">
<em>Options for bitmap assets</em></p>
<p>First, ensure the “scales” option in the attributes menu is set to “individual scales”. This is the default option, and it will show you three slots that you should fill:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/1_05iKsfSZqTVZh8w3t8ZWFA-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Drag and drop your three copies of your image here</em></p>
<p>Second, find an image that you want to use in your app. Let’s assume it’s <a target="_blank" href="https://www.flaticon.com/free-icon/stones_1209405#term=zen&amp;page=1&amp;position=25">this icon</a>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/1_fxICo0KKb-KBcfmpOYPuuA.png" alt="Image" width="600" height="400" loading="lazy">
<em>Icons of a tower of three stones and a candle</em></p>
<p>Wow that’s big. It’s because I downloaded the 512 pixel version from the site. However I only want the image to be 20 x 20 pixels in my app. To convert the image to 20 pixels, I’ll resize it in Preview.</p>
<p>Make three copies of the original image. The names of your image should look something like this: <code>zen.png</code>, <code>zen@2x.png</code>, <code>zen@3x.png</code>. The important part is that the files all have the same name (here I’m using <code>zen</code>), and two of them end with <code>@2x</code> and <code>@3x</code>. When you use this naming convention, Xcode will be able to automatically find the correct size based on the device type.</p>
<p>Next, open the image in Preview and go to Tools &gt; Adjust size to bring up the menu below. Specify 20 x 20 pixels. Press ok and save the change. This is your base image, <code>zen.png</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/09/1_zi8aQZLqJkeerb2OgVETbg.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Do the same thing for <code>zen@2x.png</code>. Only this should be 40 x 40 pixels. One more time for <code>zen@3x.png</code>. This will be 60 x 60 pixels.</p>
<p>Now you can drag and drop the images into the correct boxes in Xcode. Done!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to convert your Xcode plugins to Xcode extensions ]]>
                </title>
                <description>
                    <![CDATA[ By Khoa Pham Xcode is an indispensable IDE for iOS and macOS developers. From the early days, the ability to build and install custom plugins had given us a huge boost in productivity. It was not long before Apple introduced Xcode extension due to pr... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-convert-your-xcode-plugins-to-xcode-extensions-ac90f32ae0e3/</link>
                <guid isPermaLink="false">66c350d15a4b1b0639bef275</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Xcode ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 11 Dec 2018 18:15:53 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/0*1koaW2o_S4P9h9-H.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Khoa Pham</p>
<p>Xcode is an indispensable IDE for iOS and macOS developers. From the early days, the ability to build and install custom plugins had given us a huge boost in productivity. It was not long before Apple introduced Xcode extension due to privacy concerns.</p>
<p>I have built a few Xcode plugins and extensions like <a target="_blank" href="https://github.com/onmyway133/XcodeWay">XcodeWay</a>, <a target="_blank" href="https://github.com/onmyway133/XcodeColorSense">XcodeColorSense</a>, <a target="_blank" href="https://github.com/onmyway133/XcodeColorSense2">XcodeColorSense2</a>, and <a target="_blank" href="https://github.com/onmyway133/Xmas">Xmas</a>. It was a rewarding experience. I learned a lot, and the productivity I gained was considerable. In this post I walkthrough how I converted my Xcode plugins to extensions, and the experience I had in doing so.</p>
<h3 id="heading-my-first-xcode-plugin-xcodeway">My first Xcode plugin: XcodeWay</h3>
<blockquote>
<p>I choose a lazy person to do a hard job. Because a lazy person will find an easy way to do it</p>
</blockquote>
<p>I really like the above <a target="_blank" href="https://www.goodreads.com/quotes/568877-i-choose-a-lazy-person-to-do-a-hard-job">quote from Bill Gates</a>. I try to avoid repetitive and boring tasks. Whenever I find myself doing the same tasks again, I write scripts and tools to automate that. Doing this takes some time, but I will be a bit lazier in the near future.</p>
<p>Besides the interest in building open source <a target="_blank" href="https://github.com/onmyway133/blog/issues/5">frameworks and tools</a>, I like to extend the IDE I’m using — mostly Xcode.</p>
<p>I first started iOS development in 2014. I wanted a quick way to navigate to many places right from Xcode with the context of the current project. There are many times we want to:</p>
<ul>
<li>open the current project folder in “Finder” to change some files</li>
<li>open Terminal to run some commands</li>
<li>open the current file in GitHub to quickly give the link to a workmate</li>
<li>or to open other folders like themes, plugins, code snippets, device logs.</li>
</ul>
<p>Every little bit of time we save each day counts.</p>
<p>I thought it would be cool idea to write an Xcode plugin that we can do all above things right inside Xcode. Instead of waiting for other people to do it, I pulled up my sleeve and wrote my first Xcode plugin — <a target="_blank" href="https://github.com/onmyway133/XcodeWay">XcodeWay</a>— and shared it as open source.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/UsaS2cDc3Lcvo0vcGZ2S3wTl9Dw7VXE4ZPlX" alt="Image" width="800" height="505" loading="lazy">
<em>XcodeWay works by creating a menu under <code>Editor</code> with lots of options to navigate to other places right from Xcode. It looks simple but there was some hard work required.</em></p>
<h3 id="heading-what-are-xcode-plugins">What are Xcode plugins?</h3>
<p>Xcode plugins are not officially supported by Xcode or recommended by Apple. There are no documents about them. The best places we can learn about them are via existing plugins’ source code and a few tutorials.</p>
<p>An Xcode plugin is just a bundle of type <code>xcplugin</code> and is placed at <code>~/Library/Application Support/Developer/Shared/Xcode/Plug-ins</code> . Xcode, when starting, will load any Xcode plugins present in this folder. Plugins are run in the same process as Xcode, so could do anything as Xcode. A bug in any plugin can cause Xcode to crash.</p>
<p>To make an Xcode plugin, create a <code>macOS Bundle</code> with one class that extends from <code>NSObject</code> , and have an initialiser that accepts <code>NSBundle</code> , for example in <a target="_blank" href="https://github.com/onmyway133/Xmas/blob/master/Xmas/Xmas.swift">Xmas</a>:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/EzOyELe5LTOCRpAtu0BsioFmMluYXqP7jdTM" alt="Image" width="800" height="589" loading="lazy"></p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Xmas</span>: <span class="hljs-title">NSObject</span> </span>{
</code></pre><pre><code>  <span class="hljs-keyword">var</span> bundle: NSBundle
</code></pre><pre><code>  init(bundle: NSBundle) {    self.bundle = bundle    <span class="hljs-built_in">super</span>.init()  }}
</code></pre><p>Inside <code>Info.plist</code>, we need to:</p>
<ul>
<li>declare this class as the main entry class for the plugin, and</li>
<li>that this bundle has no UI, because we create UI controls and add to the Xcode interface during runtime</li>
</ul>
<pre><code>&lt;key&gt;NSPrincipalClass&lt;<span class="hljs-regexp">/key&gt;&lt;string&gt;Xmas&lt;/</span>string&gt;<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">key</span>&gt;</span>XCPluginHasUI<span class="hljs-tag">&lt;/<span class="hljs-name">key</span>&gt;</span></span><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">false</span>/&gt;</span></span>
</code></pre><p>Another problem with Xcode plugins is that we have to continuously update <code>DVTPluginCompatibilityUUIDs</code> . This changes every time a new version of Xcode comes out. Without updating, Xcode will refuse to load the plugin.</p>
<h3 id="heading-what-xcode-plugins-can-do">What Xcode plugins can do</h3>
<p>Many developers build Xcode plugins because they miss specific features found in other IDEs like Sublime Text, AppCode, or Atom.</p>
<p>Since Xcode plugins are loaded in the same process as Xcode, they can do everything that Xcode can. The only limit is our imagination. We can leverage Objective C Runtime to discover private frameworks and functions. Then LLDB and Symbolic breakpoint can be used further to inspect running code and alter their behaviors. We can also use swizzling to change implementation of any running code. Writing Xcode plugins is hard — lots of guessing, and sometimes a good knowledge of assembly is required.</p>
<p>In the golden age of plugins, there was a popular plugin manager, which itself was a plugin, called <a target="_blank" href="https://github.com/alcatraz/Alcatraz">Alcatraz</a>. It could install other plugins, which basically just downloads the <code>xcplugin</code> file and moves this to the <code>Plug Ins</code> folder.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/RNeR70XwT9oTBQQxHiXMrkCfNK3EhaBzyhoh" alt="Image" width="800" height="739" loading="lazy"></p>
<p>To get a sense of what plugins can do, let’s take a look at some popular plugins.</p>
<h4 id="heading-xvim">Xvim</h4>
<p>First in the list is <a target="_blank" href="https://github.com/XVimProject/XVim">Xvim</a>, which adds Vim keybindings right inside Xcode. It supports mostly all of the keybindings that we used to have in Terminal.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/5uRzbVcVrF7YfLPfEFWaRaMM9V3ZPmi9kqvU" alt="Image" width="800" height="449" loading="lazy"></p>
<h4 id="heading-scxcodeminimap">SCXcodeMiniMap</h4>
<p>If you miss MiniMap mode in Sublime Text, you can use <a target="_blank" href="https://github.com/stefanceriu/SCXcodeMiniMap">SCXcodeMiniMap</a> to add a right map panel inside Xcode editor.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/epSJCC4KrLrDlqW5Q80t0tUeGSpyYZGRyMPU" alt="Image" width="800" height="477" loading="lazy"></p>
<h4 id="heading-fuzzyautocompleteplugin">FuzzyAutocompletePlugin</h4>
<p>Before version 9, Xcode didn’t have proper auto completion — it was just based on prefix. That was where <a target="_blank" href="https://github.com/FuzzyAutocomplete/FuzzyAutocompletePlugin">FuzzyAutocompletePlugin</a> shone. It performs fuzzy auto completion based on the hidden <code>IDEOpenQuicklyPattern</code> feature in Xcode.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/jDyipJzu0YigAbvz7gteWoc2HFcr3Cag2tNk" alt="Image" width="800" height="352" loading="lazy"></p>
<h4 id="heading-ksimagenamed-xcode">KSImageNamed-Xcode</h4>
<p>To display a bundle image inside <code>UIImageView</code>, we often use the <code>imageNamed</code> method. But remembering exactly the name of the image file is hard. <a target="_blank" href="https://github.com/ksuther/KSImageNamed-Xcode">KSImageNamed-Xcode</a> is here to help. You will get a list of auto-suggested image names when you begin to type.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/s4A8NgJ6afZV8E9kpeCZ6EH8KkZyNPtq6Pxs" alt="Image" width="800" height="314" loading="lazy"></p>
<h4 id="heading-colorsense-for-xcode">ColorSense-for-Xcode</h4>
<p>Another itch during development is to work with <code>UIColor</code> , which uses RGBA color space. We don’t get a visual indicator of the color that we specify, and manually performing checking can be time consuming. Luckily there is <a target="_blank" href="https://github.com/omz/ColorSense-for-Xcode">ColorSense-for-Xcode</a> which shows the color being used and the color picker panel to easily select the right color.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/rVjJEdtXDZ1eFDHejstEgDLtdllhDFCayaM3" alt="Image" width="800" height="506" loading="lazy"></p>
<h4 id="heading-linkedconsole">LinkedConsole</h4>
<p>In AppCode, we can jump to a specific line in the file that is logged inside the console. If you miss this feature in Xcode, you can use <a target="_blank" href="https://github.com/krzysztofzablocki/LinkedConsole">LinkedConsole</a>. This enables clickable links inside Xcode console so we can jump to that file instantly.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/5Qwhb8nHh4GIdWQCtDIw-eajwUucu2tkExcf" alt="Image" width="800" height="377" loading="lazy"></p>
<h3 id="heading-the-hard-work-behind-xcode-plugins">The hard work behind Xcode plugins</h3>
<p>Making an Xcode plugin is not easy. Not only do we need to know macOS programming, but we also need to dive deep into Xcode view hierarchy. We need to explore private frameworks and APIs in order to inject the feature we want.</p>
<p>There are very few tutorials on how to make plugins but, luckily, most plugins are open source so we can understand how they work. Since I have made a few plugins, I can give some technical details about them.</p>
<p>Xcode plugins are done usually with two private frameworks: <code>DVTKit</code> and <code>IDEKit</code> . System frameworks are at <code>/System/Library/PrivateFrameworks</code> but the frameworks that Xcode uses exclusively are under <code>/Applications/Xcode.app/Contents/</code> , there you can find <code>Frameworks</code> , <code>OtherFrameworks</code> and <code>SharedFrameworks</code>.</p>
<p>There is a tool <a target="_blank" href="https://github.com/nygard/class-dump">class-dump</a> that can generate headers from the Xcode app bundle. With the class names and methods, you can call <code>NSClassFromString</code> to get the class from the name.</p>
<h4 id="heading-swizzling-dvtbezelalertpanel-framework-in-xmas">Swizzling DVTBezelAlertPanel framework in Xmas</h4>
<p>Christmas has always given me a special feeling, so I decided to make <a target="_blank" href="https://github.com/onmyway133/Xmas">Xmas</a>, which shows a random Christmas picture instead of the default alert view. The class used to render that view is <a target="_blank" href="https://github.com/luisobo/Xcode-RuntimeHeaders/blob/master/DVTKit/DVTBezelAlertPanel.h">DVTBezelAlertPanel</a> inside the DVTKit framework. <a target="_blank" href="https://medium.com/fantageek/xmas-9522c2c88db3">My article on building that plugin is here.</a></p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/sHzqA7m3ACnL-pRYeN7SfDfo0qilF06HoxQU" alt="Image" width="800" height="445" loading="lazy"></p>
<p>With Objective C Runtime, there is a technique called swizzling, which can change and switch implementation and method signature of any running classes and methods.</p>
<p>Here, in order to change the content of that alert view, we need to swap the <a target="_blank" href="https://github.com/onmyway133/Xmas/blob/master/Xmas/Xmas.swift">initialiser</a> <code>initWithIcon:message:parentWindow:duration:</code> with our own method. We do that early by listening to <code>NSApplicationDidFinishLaunchingNotification</code> which is notified when a macOS plugin, in this case Xcode, launches.</p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">func</span> <span class="hljs-title">swizzleMethods</span>() </span>{    guard <span class="hljs-keyword">let</span> originalClass = NSClassFromString(<span class="hljs-string">"DVTBezelAlertPanel"</span>) <span class="hljs-keyword">as</span>? NSObject.Type <span class="hljs-keyword">else</span> {        <span class="hljs-keyword">return</span>    }
</code></pre><pre><code><span class="hljs-keyword">do</span> {        <span class="hljs-keyword">try</span> originalClass.jr_swizzleMethod(<span class="hljs-string">"initWithIcon:message:parentWindow:duration:"</span>,            <span class="hljs-attr">withMethod</span>: <span class="hljs-string">"xmas_initWithIcon:message:parentWindow:duration:"</span>)    }    <span class="hljs-keyword">catch</span> {        Swift.print(<span class="hljs-string">"Swizzling failed"</span>)    }}
</code></pre><p>I initially liked to do everything in Swift. But it’s tricky to use the s<a target="_blank" href="https://stackoverflow.com/questions/34317766/how-to-swizzle-init-in-swift">wizzle init method in Swift</a>, so the quickest way is to do that in <a target="_blank" href="https://github.com/onmyway133/xmas/blob/master/Xmas/NSObject%2BXmas.m">Objective C</a>. Then we simply traverse the view hierarchy to find the <code>NSVisualEffectView</code> inside <code>NSPanel</code> to update the image.</p>
<h4 id="heading-interacting-with-dvtsourcetextview-in-xcodecolorsense">Interacting with DVTSourceTextView in XcodeColorSense</h4>
<p>I work mostly with hex colors and I want a quick way to see the color. So I built XcodeColorSense — it supports hex color, RGBA, and named color.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/yfDV0dfqfsURAljntQXt1LymFG1AztzKT5Xq" alt="Image" width="800" height="440" loading="lazy"></p>
<p>The idea is simple. Parse the string to see if the user is typing something related to <code>UIColor</code>, and show a small overlay view with that color as background. The text view that Xcode uses is of type <code>DVTSourceTextView</code> in <code>DVTKit</code> framework. We also need to listen to <code>NSTextViewDidChangeSelectionNotification</code> which is triggered whenever any <code>NSTextView</code> content is <a target="_blank" href="https://github.com/onmyway133/XcodeColorSense/blob/master/XcodeColorSense/XcodeColorSense.swift">changed</a>.</p>
<pre><code>func listenNotification() {  NSNotificationCenter.defaultCenter().addObserver(self, <span class="hljs-attr">selector</span>: #selector(handleSelectionChange(_:)), <span class="hljs-attr">name</span>: NSTextViewDidChangeSelectionNotification, <span class="hljs-attr">object</span>: nil)}
</code></pre><pre><code>func handleSelectionChange(note: NSNotification) {  guard <span class="hljs-keyword">let</span> DVTSourceTextView = NSClassFromString(<span class="hljs-string">"DVTSourceTextView"</span>) <span class="hljs-keyword">as</span>? NSObject.Type,    object = note.object where object.isKindOfClass(DVTSourceTextView.self),    <span class="hljs-keyword">let</span> textView = object <span class="hljs-keyword">as</span>? NSTextView  <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }
</code></pre><pre><code>self.textView = textView}
</code></pre><p>I had a Matcher architecture so we can detect different kinds of <code>UIColor</code> constructions — for example <code>[HexMatcher](https://github.com/onmyway133/XcodeColorSense/blob/master/XcodeColorSense/Matcher/HexMatcher.swift)</code> .</p>
<pre><code>public struct HexMatcher: Matcher {
</code></pre><pre><code>func check(line: <span class="hljs-built_in">String</span>, <span class="hljs-attr">selectedText</span>: <span class="hljs-built_in">String</span>) -&gt; (color: NSColor, <span class="hljs-attr">range</span>: NSRange)? {    <span class="hljs-keyword">let</span> pattern1 = <span class="hljs-string">"\"#?[A-Fa-f0-9]{6}\""</span>    <span class="hljs-keyword">let</span> pattern2 = <span class="hljs-string">"0x[A-Fa-f0-9]{6}"</span>
</code></pre><pre><code><span class="hljs-keyword">let</span> ranges = [pattern1, pattern2].flatMap {      <span class="hljs-keyword">return</span> Regex.check(line, <span class="hljs-attr">pattern</span>: $<span class="hljs-number">0</span>)    }
</code></pre><pre><code>guard <span class="hljs-keyword">let</span> range = ranges.first      <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> nil }
</code></pre><pre><code><span class="hljs-keyword">let</span> text = (line <span class="hljs-keyword">as</span> NSString).substringWithRange(range).replace(<span class="hljs-string">"0x"</span>, <span class="hljs-attr">with</span>: <span class="hljs-string">""</span>).replace(<span class="hljs-string">"\""</span>, <span class="hljs-attr">with</span>: <span class="hljs-string">""</span>)    <span class="hljs-keyword">let</span> color = NSColor.hex(text)
</code></pre><pre><code><span class="hljs-keyword">return</span> (color: color, <span class="hljs-attr">range</span>: range)  }}
</code></pre><p>To render the overlay, we use <code>NSColorWell</code> which is good for showing a view with background. The position is determined by calling <code>firstRectForCharacterRange</code> and some point conversions with <code>convertRectFromScreen</code> and <code>convertRect</code> .</p>
<h4 id="heading-using-nstask-and-ideworkspacewindowcontroller-in-xcodeway">Using NSTask and IDEWorkspaceWindowController in XcodeWay</h4>
<p>Finally, my beloved <a target="_blank" href="https://github.com/onmyway133/XcodeWay/tree/1.0">XcodeWay</a>.</p>
<p>I found myself needing to go to different places from Xcode with the context of the current project. So I built XcodeWay as a plugin that adds lots of handy menu options under <code>Window</code>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/NWfrvwX1RWXLoUDS24gETXJ8PwZLf5J1bUCN" alt="Image" width="800" height="500" loading="lazy"></p>
<p>Since the plugin runs in the same Xcode process, it has access to the main menu <code>NSApp.mainMenu?.itemWithTitle(“Window”)</code> . There we can alter the menu. XcodeWay is designed to easily extend functionalities through its <a target="_blank" href="https://github.com/onmyway133/XcodeWay/blob/1.0/XcodeWay/Navigator/Navigator.swift">Navigator</a> protocol.</p>
<pre><code>@objc protocol Navigator: NSObjectProtocol {  func navigate()  <span class="hljs-keyword">var</span> title: <span class="hljs-built_in">String</span> { get }}
</code></pre><p>For folders with a static path like Provisioning Profile <code>~/Library/MobileDevice/Provisioning Profiles</code> or User data <code>Developer/Xcode/UserData</code> , we can just construct the <code>URL</code> and call <code>NSWorkspace.sharedWorkspace().openURL</code> . For dynamic folders that vary depending on the current project, more work needs to be done.</p>
<p>How do we open the folder for the current project in Finder? The information for the current project path is kept inside <code>IDEWorkspaceWindowController</code> . This is a class that manages workspace windows in Xcode. Take a look at <a target="_blank" href="https://github.com/onmyway133/XcodeWay/blob/1.0/XcodeWay/Helper/FTGEnvironmentManager.m">EnvironmentManager</a> where we use <a target="_blank" href="https://developer.apple.com/documentation/objectivec/1418952-objc_getclass?language=objc">objc_getClass</a> to get the class definition from a string.</p>
<pre><code>self.IDEWorkspaceWindowControllerClass = objc_getClass(<span class="hljs-string">"IDEWorkspaceWindowController"</span>);
</code></pre><pre><code>NSArray *workspaceWindowControllers = [self.IDEWorkspaceWindowControllerClass valueForKey:@<span class="hljs-string">"workspaceWindowControllers"</span>];
</code></pre><pre><code>id workSpace = nil;
</code></pre><pre><code><span class="hljs-keyword">for</span> (id controller <span class="hljs-keyword">in</span> workspaceWindowControllers) {  <span class="hljs-keyword">if</span> ([[controller valueForKey:@<span class="hljs-string">"window"</span>] isEqual:[NSApp keyWindow]]) {    workSpace = [controller valueForKey:@<span class="hljs-string">"_workspace"</span>];  }}
</code></pre><pre><code>NSString * path = [[workSpace valueForKey:@<span class="hljs-string">"representingFilePath"</span>] valueForKey:@<span class="hljs-string">"_pathString"</span>];
</code></pre><p>Finally, we can utilise <code>valueForKey</code> to get the value for any property that we think exists. This way not only do we get the <a target="_blank" href="https://github.com/onmyway133/XcodeWay/blob/1.0/XcodeWay/Navigator/FTGProjectFolderNavigator.m">project path</a>, we also get the path to the opening file. So we can call <code>activateFileViewerSelectingURLs</code> on <code>NSWorkspace</code> to open Finder with that file selected. This is handy as users don’t need to look for that file in Finder.</p>
<p>Many times we want to execute some Terminal commands on the current project folder. To achieve that, we can use <code>NSTask</code> with launch pad <code>/usr/bin/open</code> and arguments <code>[@”-a”, @”Terminal”, projectFolderPath]</code> . iTerm, if configured probably, will open this in a new tab.</p>
<p>The documents for iOS 7 apps are placed in the fixed location <code>iPhone Simulator</code> inside Application Support. But, from iOS 8, every app has a unique UUID and their <a target="_blank" href="https://github.com/onmyway133/XcodeWay/blob/1.0/XcodeWay/Navigator/FTGSimulatorFolderNavigator.m">document folders</a> are hard to predict.</p>
<pre><code>~<span class="hljs-regexp">/Library/</span>Developer/CoreSimulator/Devices/<span class="hljs-number">1</span>A2FF360-B0A6<span class="hljs-number">-8127</span><span class="hljs-number">-95</span>F3<span class="hljs-number">-68</span>A6AB0BCC78/data/Container/Data/Application/
</code></pre><p>We can build a map and perform tracking to find the generated ID for the current project, or to check the plist inside each folder to compare the bundle identifier.</p>
<p>The quick solution that I came up with was to search for the most recent updated folder. Every time we build the project, or make changes inside the app, their document folder is updated. That is where we can make use of <code>NSFileModificationDate</code> to find the folder for the current project.</p>
<p>There are many hacks when working with Xcode plugins, but the results are rewarding. Every few minutes we save each day end up saving a lot of time overall.</p>
<h3 id="heading-security-and-freedom">Security and freedom</h3>
<p>With great power comes great responsibility. The fact that plugins can do whatever they want rings an alert to security. In late 2015, there was a malware attack by distributing a modified version of Xcode, called <a target="_blank" href="https://en.wikipedia.org/wiki/XcodeGhost">XcodeGhost</a>, which injects malicious code into any apps built with Xcode Ghost. The malware is believed to use the plugin mechanism among other things.</p>
<p>Like the iOS apps we download from the Appstore, macOS apps like Xcode are <a target="_blank" href="https://developer.apple.com/support/code-signing/">signed</a> by Apple when we download them from the Mac Appstore or through official Apple download links.</p>
<p><strong>Code signing your app</strong> assures users that it is from a known source and the app hasn’t been modified since it was last signed. Before your app can integrate app services, be installed on a device, or be submitted to the App Store, it must be signed with a <a target="_blank" href="https://developer.apple.com/support/technical/certificates/">certificate</a> issued by Apple</p>
<p>To avoid potential malware like this, at WWDC 2016 Apple announced the <a target="_blank" href="https://developer.apple.com/videos/play/wwdc2016/414/">Xcode Source Editor Extension</a> as the only way to load third party extensions into Xcode. This means that, from Xcode 8, plugins can’t be loaded.</p>
<h4 id="heading-source-editor-extension">Source Editor Extension</h4>
<p><a target="_blank" href="https://developer.apple.com/app-extensions/">Extension</a> is the recommended approach to safely add functionalities in restricted ways.</p>
<p>App extensions give users access to your app’s functionality and content throughout iOS and macOS. For example, your app can now appear as a widget on the Today screen, add new buttons in the Action sheet, offer photo filters within the Photos app, or display a new system-wide custom keyboard.</p>
<p>For now, the only extension to Xcode is Source Editor, which allows us to read and modify contents of a source file, as well as read and modify the current text selection within the editor.</p>
<p>Extension is a new target and runs in a different process than Xcode. This is good in that it can’t alter Xcode in any ways other than conforming to <code>XCSourceEditorCommand</code> to modify the current document content.</p>
<pre><code>protocol XCSourceEditorCommand {
</code></pre><pre><code>  func perform(<span class="hljs-keyword">with</span> invocation: XCSourceEditorCommandInvocation, <span class="hljs-attr">completionHandler</span>: @escaping (<span class="hljs-built_in">Error</span>?) -&amp;gt; Void)}
</code></pre><p><img src="https://cdn-media-1.freecodecamp.org/images/jfIwqKJH9VDhnI2H0JObOUPK8o0QlSstXqFR" alt="Image" width="800" height="580" loading="lazy"></p>
<p>Xcode 8 has lots of improvements like the new code completion features, Swift image and color literals, and snippets. This led to the deprecation of many Xcode plugins. For some indispensable plugins like XVim, this is unbearable for some people. Some old plugin features can’t be achieved with the current Source Editor Extension system.</p>
<h4 id="heading-unless-you-resign-xcode">Unless you resign Xcode</h4>
<p>A workaround to bypass the restriction from Xcode 8 for plugins, is to replace the existing Xcode signature by a technique called <a target="_blank" href="https://github.com/XVimProject/XVim2/blob/master/SIGNING_Xcode.md">resign</a>. Resigning is very easy — we just need to create a self-signed certificate and call the <code>codesign</code> command. After this, Xcode should be able to load plugins.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/95nZAgqJJKpYgm9nZT-INsndKwgDJYdl1QmD" alt="Image" width="728" height="548" loading="lazy"></p>
<pre><code>codesign -f -s MySelfSignedCertificate /Applications/Xcode.app
</code></pre><p>It is, however, <strong>not possible</strong> to submit apps built with resigned Xcode as the signature does not match the official version of Xcode. One way is to use two Xcodes: one official for distribution and one resigned for development.</p>
<h3 id="heading-moving-to-xcode-extension">Moving to Xcode extension</h3>
<p>Xcode extension is the way to go, so I started moving my plugins to extension. For Xmas, since it modifies view hierarchy, it can’t become an extension.</p>
<h4 id="heading-color-literal-in-xcodecolorsense2">Color literal in XcodeColorSense2</h4>
<p>For the color sense, I rewrote the extension from scratch, and called it <a target="_blank" href="https://github.com/onmyway133/XcodeColorSense2">XcodeColorSense2</a>. This, of course, can’t show an overlay over the current editor view. So I chose to utilize the new <code>Color literal</code> found in Xcode 8+.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/JoHeQ87KD4m-vTjhCoUy0Ua9XkaG4K9tdVj-" alt="Image" width="800" height="181" loading="lazy"></p>
<p>The color is shown in a small box. It may be hard to distinguish similar colors, so that’s why I also include the name. The code is simply about inspecting <code>selections</code> and parsing to find the color declaration.</p>
<pre><code>func perform(<span class="hljs-keyword">with</span> invocation: XCSourceEditorCommandInvocation, <span class="hljs-attr">completionHandler</span>: @escaping (<span class="hljs-built_in">Error</span>?) -&gt; Void ) -&gt; Void {    guard <span class="hljs-keyword">let</span> selection = invocation.buffer.selections.firstObject <span class="hljs-keyword">as</span>? XCSourceTextRange <span class="hljs-keyword">else</span> {      completionHandler(nil)      <span class="hljs-keyword">return</span>    }
</code></pre><pre><code><span class="hljs-keyword">let</span> lineNumber = selection.start.line
</code></pre><pre><code>guard lineNumber &lt; invocation.buffer.lines.count,      <span class="hljs-keyword">let</span> line = invocation.buffer.lines[lineNumber] <span class="hljs-keyword">as</span>? <span class="hljs-built_in">String</span> <span class="hljs-keyword">else</span> {      completionHandler(nil)      <span class="hljs-keyword">return</span>    }
</code></pre><pre><code>guard <span class="hljs-keyword">let</span> hex = findHex(string: line) <span class="hljs-keyword">else</span> {      completionHandler(nil)      <span class="hljs-keyword">return</span>    }
</code></pre><pre><code><span class="hljs-keyword">let</span> newLine = process(line: line, <span class="hljs-attr">hex</span>: hex)
</code></pre><pre><code>invocation.buffer.lines.replaceObject(at: lineNumber, <span class="hljs-attr">with</span>: newLine)
</code></pre><pre><code>completionHandler(nil)  }}
</code></pre><p>Most of the functionality is embedded inside my framework <a target="_blank" href="https://github.com/onmyway133/Farge">Farge</a>, but I can’t find a way to use the <a target="_blank" href="https://stackoverflow.com/questions/43673353/how-to-use-framework-in-xcode-source-editor-extension">framework inside Xcode extension</a>.</p>
<p>Since the extension feature is only accessible through the Editor menu, we can customise a key binding to invoke this menu item. For example I choose <code>Cmd+Ctrl+S</code> to show and hide color information.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/CznmGCwhrAIoo7eXrgN0EklxQy-L30pPVzXx" alt="Image" width="800" height="500" loading="lazy"></p>
<p>This is, of course, not intuitive compared to the original plugin, but it’s better than nothing.</p>
<h4 id="heading-how-to-debug-xcode-extensions">How to debug Xcode extensions</h4>
<p>Working and debugging extensions is straightforward. We can use Xcode to debug Xcode. The debugged version of Xcode has a gray icon.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/hB3h0Rpjc97sVm1aQKU52yNjh5sHZvCCsq1n" alt="Image" width="800" height="336" loading="lazy"></p>
<h4 id="heading-how-to-install-xcode-extensions">How to install Xcode extensions</h4>
<p>The extension must have an accompanying macOS app. This can be distributed to Mac Appstore or self-signed. <a target="_blank" href="https://medium.com/fantageek/install-xcode-8-source-editor-extension-10c9849e33b0">I’ve written an article on how to do this</a>.</p>
<p>All extensions for an app need to be explicitly enabled through “System Preferences”.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/8pLbJHO2TO0HSsTKeUnT7xwyFdy-YrzkG5Xs" alt="Image" width="656" height="444" loading="lazy"></p>
<p>The Xcode extension only works with editor for now, so we must open a source file for the <code>Editor</code> menu to have effect.</p>
<h3 id="heading-applescript-in-xcodeway">AppleScript in XcodeWay</h3>
<p>In Xcode extensions, <code>NSWorkspace</code>, <code>NSTask</code> and private class construction don’t work anymore. Since I have used Finder Sync Extension in <a target="_blank" href="https://github.com/onmyway133/FinderGo">FinderGo</a>, I thought I could try the same AppleScript scripting for Xcode extension.</p>
<p><a target="_blank" href="https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/introduction/ASLR_intro.html">AppleScript</a> is a scripting language created by Apple. It allows users to directly control scriptable Macintosh applications, as well as parts of macOS itself. You can create scripts — sets of written instructions — to automate repetitive tasks, combine features from multiple scriptable applications, and create complex workflows.</p>
<p>To try AppleScript, you can use the app Script Editor built inside macOS to write prototype functions. Function declaration starts with <code>on</code> and ends with <code>end</code> . To avoid potential conflicts with system functions, I usually use <code>my</code> as a prefix. Here is how I rely on System Events to get the home directory.</p>
<p><a target="_blank" href="https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/AutomatetheUserInterface.html">User interface scripting</a> terminology is found in the “Processes Suite” of the “System Events” scripting dictionary. This suite includes terminology for interacting with most types of user interface elements, including:</p>
<ul>
<li>windows</li>
<li>buttons</li>
<li>checkboxes</li>
<li>menus</li>
<li>radio buttons</li>
<li>text fields.</li>
</ul>
<p>In System Events, the <code>process</code> class represents a running app.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/NXmx4UIXeqYxT4qUKrc7PoNnlkIg1tEZJbH6" alt="Image" width="800" height="804" loading="lazy"></p>
<p>Many good citizen apps support AppleScript by exposing some of their functionalities, so these can be used by other apps. Here is how I get the current song from Spotify in <a target="_blank" href="https://github.com/onmyway133/Lyrics">Lyrics</a>.</p>
<pre><code>tell application <span class="hljs-string">"Spotify"</span>  set trackId to id <span class="hljs-keyword">of</span> current track <span class="hljs-keyword">as</span> string  set trackName to name <span class="hljs-keyword">of</span> current track <span class="hljs-keyword">as</span> string  set artworkUrl to artwork url <span class="hljs-keyword">of</span> current track <span class="hljs-keyword">as</span> string  set artistName to artist <span class="hljs-keyword">of</span> current track <span class="hljs-keyword">as</span> string  set albumName to album <span class="hljs-keyword">of</span> current track <span class="hljs-keyword">as</span> string  <span class="hljs-keyword">return</span> trackId &amp; <span class="hljs-string">"---"</span> &amp; trackName &amp; <span class="hljs-string">"---"</span> &amp; artworkUrl &amp; <span class="hljs-string">"---"</span> &amp; artistName &amp; <span class="hljs-string">"---"</span> &amp; albumNameend tell
</code></pre><p>To get all the possible commands of a certain app, we can open the dictionary in Script Editor. There we can learn about which functions and parameters are supported.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/8kuHy0Z79lJsdzFhn7NJuJ53iDX9cU7I30nH" alt="Image" width="800" height="689" loading="lazy"></p>
<p>If you think Objective C is hard, AppleScript is much harder. The syntax is verbose and error-prone. For your reference, here is the <a target="_blank" href="https://github.com/onmyway133/XcodeWay/blob/master/XcodeWayExtensions/Script/XcodeWayScript.scpt">whole script file</a> that powers XcodeWay.</p>
<p>To open a certain folder, tell <code>Finder</code> using <code>POSIX file</code>. I refactor every functionality into function for better code reuse.</p>
<pre><code>on myOpenFolder(myPath)tell application <span class="hljs-string">"Finder"</span>activateopen myPath <span class="hljs-keyword">as</span> POSIX fileend tellend myOpenFolder
</code></pre><p>Then, to run AppleScript inside a macOS app or extension, we need to construct an <a target="_blank" href="https://github.com/onmyway133/XcodeWay/blob/master/XcodeWayExtensions/Helper/ScriptRunner.swift">AppleScript descriptor</a> with the correct process serial number and event identifiers.</p>
<pre><code>func eventDescriptior(functionName: <span class="hljs-built_in">String</span>) -&gt; NSAppleEventDescriptor {  <span class="hljs-keyword">var</span> psn = ProcessSerialNumber(highLongOfPSN: <span class="hljs-number">0</span>, <span class="hljs-attr">lowLongOfPSN</span>: UInt32(kCurrentProcess))  <span class="hljs-keyword">let</span> target = NSAppleEventDescriptor(    descriptorType: typeProcessSerialNumber,    <span class="hljs-attr">bytes</span>: &amp;psn,    <span class="hljs-attr">length</span>: MemoryLayout&lt;ProcessSerialNumber&gt;.size  )
</code></pre><pre><code><span class="hljs-keyword">let</span> event = NSAppleEventDescriptor(    eventClass: UInt32(kASAppleScriptSuite),    <span class="hljs-attr">eventID</span>: UInt32(kASSubroutineEvent),    <span class="hljs-attr">targetDescriptor</span>: target,    <span class="hljs-attr">returnID</span>: Int16(kAutoGenerateReturnID),    <span class="hljs-attr">transactionID</span>: Int32(kAnyTransactionID)  )
</code></pre><pre><code><span class="hljs-keyword">let</span> <span class="hljs-function"><span class="hljs-keyword">function</span> = <span class="hljs-title">NSAppleEventDescriptor</span>(<span class="hljs-params">string: functionName</span>)  <span class="hljs-title">event</span>.<span class="hljs-title">setParam</span>(<span class="hljs-params">function, forKeyword: AEKeyword(keyASSubroutineName)</span>)</span>
</code></pre><pre><code><span class="hljs-keyword">return</span> event}
</code></pre><p>Other tasks, like checking the current Git remote, are a bit trickier. Many times I want to share the link of the file I’m debugging to my remote teammate, so they know what file I’m referencing. This is doable by using <code>shell script</code> inside <code>AppleScript</code> .</p>
<pre><code>on myGitHubURL()set myPath to myProjectPath()set myConsoleOutput to (<span class="hljs-keyword">do</span> shell script <span class="hljs-string">"cd "</span> &amp; quoted form <span class="hljs-keyword">of</span> myPath &amp; <span class="hljs-string">"; git remote -v"</span>)set myRemote to myGetRemote(myConsoleOutput)set myUrl to (<span class="hljs-keyword">do</span> shell script <span class="hljs-string">"cd "</span> &amp; quoted form <span class="hljs-keyword">of</span> myPath &amp; <span class="hljs-string">"; git config --get remote."</span> &amp; quoted form <span class="hljs-keyword">of</span> myRemote &amp; <span class="hljs-string">".url"</span>)set myUrlWithOutDotGit to myRemoveSubString(myUrl, <span class="hljs-string">".git"</span>)end myGitHubURL
</code></pre><p>We can use <code>quoted</code> and string concatenation to form strings. Luckily we can expose <code>Foundation</code> framework and certain classes. Here is how I expose <code>NSString</code> to take advantage of all existing functionalities. Writing string manipulation from scratch using plain AppleScript will take lots of time.</p>
<pre><code>use scripting additionsuse framework <span class="hljs-string">"Foundation"</span>property NSString : a reference to current application<span class="hljs-string">'s NSString</span>
</code></pre><p>With this we can build our other functions for string handling.</p>
<pre><code>on myRemoveLastPath(myPath)set myString to NSString<span class="hljs-string">'s stringWithString:myPathset removedLastPathString to myString'</span>s stringByDeletingLastPathComponentremovedLastPathString <span class="hljs-keyword">as</span> textend myRemoveLastPath
</code></pre><p>One cool feature that XcodeWay supports is the ability to go to the document directory for the current app in the simulator. This is handy when we need to inspect a document to check saved or cached data. The directory is dynamic so it’s hard to detect. We can, however, sort the directory for the most recently updated. Below is how we chain multiple <code>shell scripts</code> commands to find the folder.</p>
<pre><code>on myOpenDocument()set command1 to <span class="hljs-string">"cd ~/Library/Developer/CoreSimulator/Devices/;"</span>set command2 to <span class="hljs-string">"cd `ls -t | head -n 1`/data/Containers/Data/Application;"</span>set command3 to <span class="hljs-string">"cd `ls -t | head -n 1`/Documents;"</span>set command4 to <span class="hljs-string">"open ."</span><span class="hljs-keyword">do</span> shell script command1 &amp; command2 &amp; command3 &amp; command4end myOpenDocument
</code></pre><p>This feature helped me a lot when developing <a target="_blank" href="https://github.com/hyperoslo/Gallery">Gallery</a> to check whether videos and downloaded images are saved in the correct place.</p>
<p>However, none of the scripts seem to work. Scripting has always been part of macOS since 1993. But, with the advent of the Mac Appstore and security concerns, AppleScript finally got restricted in mid 2012. That was when App Sandbox was enforced.</p>
<h4 id="heading-app-sandbox">App Sandbox</h4>
<p>App Sandbox is an access control technology provided in macOS, enforced at the kernel level. It is designed to contain damage to the system and the user’s data if an app becomes compromised. Apps distributed through the Mac App Store must adopt <a target="_blank" href="https://www.objc.io/issues/14-mac/sandbox-scripting/">App Sandbox</a>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/JrY-Maab-l1wSen8kIgwgQqnqW9yd5gADtHi" alt="Image" width="641" height="241" loading="lazy"></p>
<p>For an Xcode extension to be loaded by Xcode, it must also support App Sandbox.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/aCULPMrfSJYeoPA33YmhW4Ml5vHqzH1wshZS" alt="Image" width="800" height="190" loading="lazy"></p>
<p>At the beginning of App Sandbox enforcement, we could use <a target="_blank" href="https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AppSandboxTemporaryExceptionEntitlements.html">App Sandbox Temporary Exception</a> to temporarily grant our app access to Apple Script.</p>
<p>This is now not possible.</p>
<p>The only way for AppleScript to run is if it resides inside <code>~/Library/Application Scripts</code> folder.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/ZlpA42RZZeUmtl2oBgAXU2N2dGRostKLqilr" alt="Image" width="800" height="543" loading="lazy"></p>
<h4 id="heading-how-to-install-custom-scripts">How to install custom scripts</h4>
<p>macOS apps or extensions can’t just install scripts into the Application Scripts by themselves. They need user consent.</p>
<p>One possible way to do that is to enable <code>Read/Write</code> and show a dialog using <code>NSOpenPanel</code> to ask user to select the folder to install our scripts.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/UJAyb9UOLiljUuacRZxW7Vvm1U2fvldOMM0D" alt="Image" width="800" height="576" loading="lazy"></p>
<p>For XcodeWay, I choose to provide an <a target="_blank" href="https://github.com/onmyway133/XcodeWay/blob/master/install.sh">install shell script</a> so the user has a quick way to install scripts.</p>
<pre><code>#!<span class="hljs-regexp">/bin/</span>bash
</code></pre><pre><code>set -euo pipefail
</code></pre><pre><code>DOWNLOAD_URL=https:<span class="hljs-comment">//raw.githubusercontent.com/onmyway133/XcodeWay/master/XcodeWayExtensions/Script/XcodeWayScript.scptSCRIPT_DIR="${HOME}/Library/Application Scripts/com.fantageek.XcodeWayApp.XcodeWayExtensions"</span>
</code></pre><pre><code>mkdir -p <span class="hljs-string">"${SCRIPT_DIR}"</span>curl $DOWNLOAD_URL -o <span class="hljs-string">"${SCRIPT_DIR}/XcodeWayScript.scpt"</span>
</code></pre><p>AppleScript is very powerful. All of this is made explicit so the user has complete control over which things can be done.</p>
<p>Like an extension, a script is done asynchronously in a different process using <a target="_blank" href="https://www.objc.io/issues/14-mac/xpc/">XPC</a> for inter process communication. This enhances security as a script has no access to the address space to our app or extension.</p>
<h3 id="heading-more-security-in-macos-mojave">More security in macOS Mojave</h3>
<p>This year, at WWDC 2018, Apple introduced macOS Mojave which focuses on lots of security enhancements. In the <a target="_blank" href="https://developer.apple.com/videos/play/wwdc2018/702/">Your Apps and the Future of macOS Security</a> we can learn more about new security requirement for macOS apps. One of them is the usage description for AppleEvents.</p>
<blockquote>
<p>unable to load info.plist exceptions (egpu overrides)</p>
</blockquote>
<p>We used to declare usage description for many permissions in iOS, like photo library, camera, and push notifications. Now we need to declare the usage description for AppleEvents.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/qCcXKO1fvLMoI07d04f1UudrLxapIeglYZk0" alt="Image" width="747" height="290" loading="lazy">
_Source: [https://www.felix-schwarz.org/blog/2018/08/new-apple-event-apis-in-macos-mojave](https://www.felix-schwarz.org/blog/2018/08/new-apple-event-apis-in-macos-mojave" rel="noopener" target="<em>blank" title=")</em></p>
<p>The first time our extension tries to execute some AppleScript commands, the above dialog is shown to ask for user consent. User can grant or deny permission, but for Xcode please say yes ?</p>
<p>The fix for us is to declare <code>NSAppleEventsUsageDescription</code> in our app target. We only need to declare in the app target, not in the extension target.</p>
<pre><code>&lt;key&gt;NSAppleEventsUsageDescription&lt;<span class="hljs-regexp">/key&gt;&lt;string&gt;Use AppleScript to open folders&lt;/</span>string&gt;
</code></pre><h3 id="heading-where-to-go-from-here">Where to go from here</h3>
<p>Huff huff, whew! Thanks for following such a long journey. Making frameworks and tools take lots of time, especially plugins and extensions — we have to continuously change to adapt them to new operating systems and security requirements. But it is a rewarding process, as we’ve learned more and have some tools to save our precious time.</p>
<p>For your reference, here are my extensions which are fully open source.</p>
<ul>
<li><a target="_blank" href="https://github.com/onmyway133/XcodeWay">XcodeWay</a></li>
<li><a target="_blank" href="https://github.com/onmyway133/XcodeColorSense2">XcodeColorSense2</a></li>
</ul>
<p>I hope you find something useful in the post. Here are some resources to help explore Xcode extensions further:</p>
<ul>
<li><a target="_blank" href="https://nshipster.com/xcode-plugins/">Xcode Plugins by NSHipster</a></li>
<li><a target="_blank" href="http://merowing.info/2015/12/writing-xcode-plugin-in-swift/">Writing Xcode plugin in Swift</a></li>
<li><a target="_blank" href="https://medium.com/rocknnull/xcode-8-plugins-alcatraz-the-end-of-an-era-ea6e63617d14">Xcode 8 Plugins (Alcatraz) — The end of an era</a></li>
<li><a target="_blank" href="https://developer.apple.com/videos/play/wwdc2016/414/">Using and Extending the Xcode Source Editor</a></li>
<li><a target="_blank" href="https://github.com/XVimProject/XVim2/blob/master/why_resign_xcode.md">Why do I need to resign Xcode to use XVim2</a></li>
</ul>
<p>If you like this post, consider visiting <a target="_blank" href="https://github.com/onmyway133/blog/issues/165">my other articles</a> and <a target="_blank" href="https://onmyway133.github.io/">apps</a> ?</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
