<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Objective-C on kunat.dev</title>
    <link>https://kunat.dev/tags/objective-c/</link>
    <description>Recent content in Objective-C on kunat.dev</description>
    <generator>Hugo -- 0.147.5</generator>
    <language>en-us</language>
    <copyright>2025 kunat.dev</copyright>
    <lastBuildDate>Tue, 03 Jun 2025 16:50:49 +0200</lastBuildDate>
    <atom:link href="https://kunat.dev/tags/objective-c/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Adding Swift Package Manager Support to a Legacy Objective-C Project</title>
      <link>https://kunat.dev/notes/spm-support-objc-project/</link>
      <pubDate>Tue, 03 Jun 2025 16:50:49 +0200</pubDate>
      <guid>https://kunat.dev/notes/spm-support-objc-project/</guid>
      <description>&lt;p&gt;I recently needed to add Swift Package Manager support to a legacy package that one of my projects was using. The package was originally distributed with CocoaPods. The primary reason for migrating from CocoaPods to SPM is that CocoaPods entered &lt;a href=&#34;https://blog.cocoapods.org/CocoaPods-Support-Plans/&#34; target=&#34;_blank&#34; &gt;maintenance mode&lt;/a&gt; a few months ago. Removing it will future-proof our projects and allow us to use the latest features, such as the &lt;a href=&#34;https://dimillian.medium.com/why-you-should-use-xcode-16-buildable-folders-instead-of-groups-6f438611914d&#34; target=&#34;_blank&#34; &gt;buildable folders&lt;/a&gt; introduced in Xcode 16.&lt;/p&gt;
&lt;h2 id=&#34;assumptions&#34;&gt;Assumptions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Since this was an internal package, I did not need to maintain CocoaPods support. The goal was to replace it entirely with SPM. It is certainly possible to keep both, but that would require some additional work.&lt;/li&gt;
&lt;li&gt;The project I was working on is considered legacy; no one has touched it in about six years. Once this task is complete, I hope no one will need to update it for another half-dozen years. This allowed me to take some shortcuts, like integrating a third-party dependency directly into the codebase instead of spending time updating it to the latest version.&lt;/li&gt;
&lt;li&gt;All internal dependencies of your framework already support SPM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that said, let&amp;rsquo;s get started.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I recently needed to add Swift Package Manager support to a legacy package that one of my projects was using. The package was originally distributed with CocoaPods. The primary reason for migrating from CocoaPods to SPM is that CocoaPods entered <a href="https://blog.cocoapods.org/CocoaPods-Support-Plans/" target="_blank" >maintenance mode</a> a few months ago. Removing it will future-proof our projects and allow us to use the latest features, such as the <a href="https://dimillian.medium.com/why-you-should-use-xcode-16-buildable-folders-instead-of-groups-6f438611914d" target="_blank" >buildable folders</a> introduced in Xcode 16.</p>
<h2 id="assumptions">Assumptions</h2>
<ul>
<li>Since this was an internal package, I did not need to maintain CocoaPods support. The goal was to replace it entirely with SPM. It is certainly possible to keep both, but that would require some additional work.</li>
<li>The project I was working on is considered legacy; no one has touched it in about six years. Once this task is complete, I hope no one will need to update it for another half-dozen years. This allowed me to take some shortcuts, like integrating a third-party dependency directly into the codebase instead of spending time updating it to the latest version.</li>
<li>All internal dependencies of your framework already support SPM.</li>
</ul>
<p>With that said, let&rsquo;s get started.</p>
<h2 id="how">How?</h2>
<p>I&rsquo;ll assume your framework has no internal dependencies that require the same SPM treatment. If it does, start with the bottom-most dependency and work your way up.</p>
<h3 id="external-dependencies">External Dependencies</h3>
<p>The first step is to update all external dependencies to use SPM.</p>
<p>In my case, one of the dependencies was <a href="https://github.com/mxcl/PromiseKit" target="_blank" >PromiseKit</a>, which was stuck six major versions behind the latest release. Since the project was considered legacy and no further development was planned, I decided to cut some corners.</p>
<p>Instead of spending time updating PromiseKit from version 1 through 7, I opted to add SPM support to the version my project was currently using. This approach required significantly less work and proved to be the right choice.</p>
<h3 id="removing-the-old-dependency-manager">Removing the Old Dependency Manager</h3>
<p>With all dependencies migrated to SPM, you should now be able to remove the old dependency manager from your project.</p>
<h3 id="adding-a-swift-package-manifest">Adding a Swift Package Manifest</h3>
<p>Next, initialize a new Swift package in your project&rsquo;s root directory:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>swift package init
</span></span></code></pre></div><p>This will create a <code>Package.swift</code> file. Here is a basic configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#75715e">// swift-tools-version: 6.1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">import</span> <span style="color:#a6e22e">PackageDescription</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">let</span> package = Package(
</span></span><span style="display:flex;"><span>    name: <span style="color:#e6db74">&#34;MyPackage&#34;</span>,
</span></span><span style="display:flex;"><span>    products: [
</span></span><span style="display:flex;"><span>        .library(
</span></span><span style="display:flex;"><span>            name: <span style="color:#e6db74">&#34;MyPackage&#34;</span>,
</span></span><span style="display:flex;"><span>            targets: [<span style="color:#e6db74">&#34;MyPackage&#34;</span>]),
</span></span><span style="display:flex;"><span>    ],
</span></span><span style="display:flex;"><span>    targets: [
</span></span><span style="display:flex;"><span>        .target(
</span></span><span style="display:flex;"><span>            name: <span style="color:#e6db74">&#34;MyPackage&#34;</span>),
</span></span><span style="display:flex;"><span>        .testTarget(
</span></span><span style="display:flex;"><span>            name: <span style="color:#e6db74">&#34;MyPackageTests&#34;</span>,
</span></span><span style="display:flex;"><span>            dependencies: [<span style="color:#e6db74">&#34;MyPackage&#34;</span>]
</span></span><span style="display:flex;"><span>        ),
</span></span><span style="display:flex;"><span>    ]
</span></span><span style="display:flex;"><span>)
</span></span></code></pre></div><p>Move your project&rsquo;s source files to <code>Sources/MyPackage</code> and try to build the project. You will likely encounter one of the following errors:</p>
<pre tabindex="0"><code>SomeHeaderFile.h:19:9 &#39;AnotherHeaderFile.h&#39; file not found
</code></pre><p>or</p>
<pre tabindex="0"><code>public headers (&#34;include&#34;) directory path for &#39;MyPackage&#39; is invalid or not contained in the target
</code></pre><p>These errors indicate that the compiler cannot locate your project&rsquo;s header files. By default, SPM looks for public headers in an <code>include</code> directory.</p>
<p>Create an <code>include</code> directory inside <code>Sources/MyPackage</code> and move all of your project&rsquo;s public headers there.</p>
<p>If this structure doesn&rsquo;t suit your project, you can define a custom path for your public headers by specifying <code>publicHeadersPath</code> in your <code>Package.swift</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span>    targets: [
</span></span><span style="display:flex;"><span>        .target(
</span></span><span style="display:flex;"><span>            name: <span style="color:#e6db74">&#34;MyPackage&#34;</span>,
</span></span><span style="display:flex;"><span>            publicHeadersPath: <span style="color:#e6db74">&#34;some/custom/path&#34;</span>
</span></span><span style="display:flex;"><span>        ),
</span></span><span style="display:flex;"><span>        .testTarget(
</span></span><span style="display:flex;"><span>            name: <span style="color:#e6db74">&#34;MyPackageTests&#34;</span>,
</span></span><span style="display:flex;"><span>            dependencies: [<span style="color:#e6db74">&#34;MyPackage&#34;</span>]
</span></span><span style="display:flex;"><span>        ),
</span></span><span style="display:flex;"><span>    ]
</span></span></code></pre></div><p><strong>How do I locate my project&rsquo;s public headers?</strong></p>
<p>Your project most likely had an Xcode project file (<code>.xcproj</code>) before you started adding SPM support. You can find a list of your public headers in the &ldquo;Build Phases&rdquo; tab, under the &ldquo;Headers&rdquo; section.</p>
<p><img alt="changedetection" loading="lazy" src="/notes/images/spm-objc-public-headers.jpg"></p>
<p>After correctly configuring the public header files, your project might build. If it still doesn&rsquo;t, you may have other header files that need to be discoverable. If that&rsquo;s the case, you&rsquo;ll need to add search paths for your private header files using <code>headerSearchPath</code> in your cSettings:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span>.target(
</span></span><span style="display:flex;"><span>    name: <span style="color:#e6db74">&#34;MyPackage&#34;</span>,
</span></span><span style="display:flex;"><span>    cSettings: [
</span></span><span style="display:flex;"><span>        .headerSearchPath(<span style="color:#e6db74">&#34;Payments&#34;</span>),
</span></span><span style="display:flex;"><span>        .headerSearchPath(<span style="color:#e6db74">&#34;Payments/ApplePayPaymentsService&#34;</span>),
</span></span><span style="display:flex;"><span>        .headerSearchPath(<span style="color:#e6db74">&#34;Transactions/Components&#34;</span>)
</span></span><span style="display:flex;"><span>    ]),
</span></span></code></pre></div><p>It&rsquo;s up to you whether you want to group all private header files in a single directory (<code>.headerSearchPath(&quot;Path/To/My/Private/Headers&quot;)</code>) or add all existing directories one by one using their current locations as I did in the snippet above.</p>
<p>With that done, you should now be able to build your project.</p>
<h2 id="troubleshooting">Troubleshooting</h2>
<p>In my case, after migrating all dependencies to SPM and adding the package manifest, I was able to delete the Xcode project file entirely. If that is not the case for you, you might encounter additional issues.</p>
<p>One common problem is the error <code>fatal error: framework '&lt;some_framework&gt;' not found</code> when trying to import an SPM dependency into an Objective-C codebase in a project managed via an Xcode project file (<code>.xcproj</code>).</p>
<p>In this situation, you may need to experiment with your project settings. <a href="https://developer.apple.com/forums/thread/120152" target="_blank" >This thread</a> on the Apple Developer Forums is an good starting point.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Once these steps are completed, you should be able to build your project. If you add your new package as a dependency via SPM, you can import it like any other Swift package. The same rules apply.</p>
<p><strong>Swift:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-swift" data-lang="swift"><span style="display:flex;"><span><span style="color:#66d9ef">import</span> <span style="color:#a6e22e">MyPackage</span>
</span></span></code></pre></div><p><strong>Objective-C:</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-objectivec" data-lang="objectivec"><span style="display:flex;"><span>@import MyPackage;
</span></span></code></pre></div><h2 id="resources">Resources</h2>
<p>What helped me the most was looking at examples of existing Objective-C projects with SPM support. The following repositories are worth exploring:</p>
<ul>
<li><a href="https://github.com/PSPDFKit/PDFXKit" target="_blank" >PSPDFKit/PDFXKit</a>: A drop-in replacement for Apple&rsquo;s PDFKit, powered by the PSPDFKit framework.</li>
<li><a href="https://github.com/AliSoftware/OHHTTPStubs" target="_blank" >AliSoftware/OHHTTPStubs</a>: A library to easily stub your network requests.</li>
<li><a href="https://github.com/Mantle/Mantle" target="_blank" >Mantle/Mantle</a>: Model framework for Cocoa and Cocoa Touch</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Getting Back Up to Speed with Objective-C in 2025</title>
      <link>https://kunat.dev/notes/getting-up-to-speed-with-objectivec/</link>
      <pubDate>Thu, 03 Apr 2025 10:10:52 +0200</pubDate>
      <guid>https://kunat.dev/notes/getting-up-to-speed-with-objectivec/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve mostly moved away from using Objective-C over the years. While it still appears in some of the projects I work on, it’s been quite some time since I last had to work on a feature written entirely in Objective-C. These days, I typically encounter it when integrating a new feature written in Swift into an older codebase.&lt;/p&gt;
&lt;p&gt;Recently, however, I needed to brush up on Objective-C for a job I was interviewing for.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve mostly moved away from using Objective-C over the years. While it still appears in some of the projects I work on, it’s been quite some time since I last had to work on a feature written entirely in Objective-C. These days, I typically encounter it when integrating a new feature written in Swift into an older codebase.</p>
<p>Recently, however, I needed to brush up on Objective-C for a job I was interviewing for.</p>
<p>Below is a list of strategies that helped me quickly get back up to speed with Objective-C in about 6–8 hours. The list is fairly comprehensive—it should refresh your memory and might even teach you something new. That said, if you’re completely new to the language, YMMV.</p>
<h2 id="language-fundamentals-objective-c-for-swift-developers-by-paul-hudson">Language Fundamentals: <em>Objective-C for Swift Developers</em> by Paul Hudson</h2>
<p>I can’t recommend <a href="https://www.hackingwithswift.com/store/objective-c-for-swift-developers" target="_blank" >this book</a> enough. It’s only 150 pages long and covers a wide range of language features and quirks you’ve likely forgotten—<a href="http://fuckingblocksyntax.com" target="_blank" >block syntax, anyone?</a></p>
<p>One tip: have a playground project open in Xcode while you read. If you’re not sure how to create an Objective-C project in Xcode 16, use <a href="/notes/xcode-objc-project-template/" >this guide</a>.</p>
<h2 id="leetcode-challenges">LeetCode Challenges</h2>
<p>LeetCode doesn’t support Objective-C directly in its web interface, but that’s not an issue in the age of LLMs!</p>
<p>Since my goal was to refresh my knowledge of basic language features, I focused primarily on easy challenges. By &ldquo;basic language features,&rdquo; I mean working with strings, arrays, and simple data structures.</p>
<blockquote>
<p>I definitely didn’t want to spend time solving complex problems like counting islands in a binary matrix (looking at you, “Number of Islands II,” problem #305).</p></blockquote>
<p>I selected a few easy problems and worked through them in Xcode. <a href="https://claude.ai/" target="_blank" >Claude</a> was particularly helpful in generating test cases to validate my solutions.</p>
<h2 id="working-with-large-codebases">Working with Large Codebases</h2>
<p>The final exercise was exploring a larger project written entirely in Objective-C. I started with the App Delegate and used an LLM to answer questions about anything that seemed unclear. I focused on understanding how common patterns were implemented—things like singletons, callback-based APIs, and delegate patterns.</p>
<p>Here are some projects I recommend checking out:</p>
<ul>
<li><a href="https://github.com/adium/adium" target="_blank" >Adium</a></li>
<li><a href="https://github.com/Kaakati/iOS-Objective-C-Library" target="_blank" >A curated list of awesome iOS ecosystem libraries written in Objective-C</a></li>
</ul>
<hr>
<p>That’s it! I was genuinely surprised by how much fun this process turned out to be—and also by how much I’d forgotten about Objective-C. Hopefully, this time around, the block syntax will stick with me longer!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Creating a New Objective-C Project in Xcode 16</title>
      <link>https://kunat.dev/notes/xcode-objc-project-template/</link>
      <pubDate>Tue, 25 Mar 2025 17:52:35 +0100</pubDate>
      <guid>https://kunat.dev/notes/xcode-objc-project-template/</guid>
      <description>&lt;p&gt;Update: 26/03/25&lt;/p&gt;
&lt;p&gt;It looks like Objective-C is still an option in the default iOS project template. You can access it after setting the &lt;em&gt;Interface&lt;/em&gt; to &amp;ldquo;Storyboard&amp;rdquo;. I hadn&amp;rsquo;t realized these dropdown menus were interconnected.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;hello there&#34; loading=&#34;lazy&#34; src=&#34;https://kunat.dev/notes/images/xcode-objc-project-template-2.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;All credit goes to &lt;a href=&#34;https://douglashill.co&#34; target=&#34;_blank&#34; &gt;Douglas&lt;/a&gt; for spotting this!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;tl;dr use macOS → Application → Game or Command Line Tool&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;hello there&#34; loading=&#34;lazy&#34; src=&#34;https://kunat.dev/notes/images/objc-xcode-project-template.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;Recently I wanted to refresh my memory on Objective-C. My first thought was to open Xcode, create a new project with language set to Objective-C and play with it. To my surprise, none of the iOS Application project templates allow you to select any other language than Swift.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Update: 26/03/25</p>
<p>It looks like Objective-C is still an option in the default iOS project template. You can access it after setting the <em>Interface</em> to &ldquo;Storyboard&rdquo;. I hadn&rsquo;t realized these dropdown menus were interconnected.</p>
<p><img alt="hello there" loading="lazy" src="/notes/images/xcode-objc-project-template-2.jpg"></p>
<p>All credit goes to <a href="https://douglashill.co" target="_blank" >Douglas</a> for spotting this!</p>
<hr>
<p>tl;dr use macOS → Application → Game or Command Line Tool</p>
<p><img alt="hello there" loading="lazy" src="/notes/images/objc-xcode-project-template.jpg"></p>
<p>Recently I wanted to refresh my memory on Objective-C. My first thought was to open Xcode, create a new project with language set to Objective-C and play with it. To my surprise, none of the iOS Application project templates allow you to select any other language than Swift.</p>
<p>I (mistakenly) assumed that Apple must have removed Objective-C from all templates altogether. I ended up searching for some open-source Objective-C project that I could use as a starting point.</p>
<p>Later on I learned that Objective-C language options are still alive and well in some templates for macOS.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
