Thoughts on Swift and Objective-C

July 4 2022 by Jeff Johnson

I want to start by saying that I speak only for myself. I don't speak for other Objective-C programmers, nor do they speak for me. We are not of one mind. The same is true of Swift programmers: some of them seem quite reasonable to me, and others seem rather… fanatical. Regardless, it's almost impossible to have a productive discussion about programming languages on social media, given the constraints of brevity, and also given the freedom of fanatics to barge in on the discussion at any time, effectively ruining it. This is why I'm taking the time to expound here, free of those constraints. My aim is not to persuade anyone to choose a particular programming language, just to explain my point of view in reasonable terms, without the caricatures and insults regurgitated on social media.

It may seem to some people that I'm fanatical about Objective-C, but I actually don't like any programming language. (Maybe Pascal? IIRC it was pretty nice, though my memory of it is very hazy. Could be nostalgia.) I find it odd when people say they love a programming language. In contrast, I take a utilitarian approach to programming, not an emotional one. My joy comes from shipping a product that users enjoy (and from making a living doing it!), not from writing code per se. Maybe that's because programming was not my first choice of career. Or my second choice, or third choice. That's a story for another day. (Never.) Anyway, I fully recognize that Objective-C has flaws — all languages do — and before Swift was introduced in 2014, I had always wanted something somewhat different, like the "Objective-C without the C" that Hair Force One falsely claimed was embodied by Swift. In retrospect, I've come to recognize that "with the C" is not bug but a feature. Nonetheless, I don't consider Objective-C to be an ideal language. It mixes idealism with pragmatism, inherently a compromise position. I've used many programming languages over my life, as appropriate in the context, and nowadays as a web browser extension developer I tend to write more JavaScript than native code. (By the way, JavaScript is the absolute worst IMO LOL.) I'm certainly not committed to Objective-C forever. It wasn't my first language or my last.

Although I didn't jump on the Swift bandwagon in 2014, I didn't refuse to learn Swift either. In 2017 I wrote an open source Swift app, just to show that I could do it. (This is back when I was still looking for a job.) By popular demand, I also wrote Swift sample code for my long-running Working Without a Nib series of blog posts describing how to create a Mac app, and specifically a Mac app's main menu, without nibs/xibs/storyboards. In fact I've written several blog posts about Swift programming. I can't say I'm a Swift expert, but you can't say I'm a Swift ignoramus. Having used Swift a bit, I ultimately didn't find a reason to switch full-time from Objective-C to Swift. I think I share one opinion with many Swift programmers, which is that it's difficult to fluently alternate between Objective-C and Swift. After writing a lot of Swift, you tend to lose your Objective-C habits, and vice versa. For the sake of maximum productivity, writing both languages simultaneously is the worst of both worlds — especially in the same project! — and it's probably best to choose one language or the other for most of your work. I personally chose to stick with Objective-C.

Perhaps I was unlucky, but my Swift experience turned out to be unpleasant. My main complaint is that the Swift team killed my Swift app. In other words, the app will no longer build with Swift version 5, giving the compiler error "cannot override with a stored property", and it would require a significant refactor of the app to avoid the compiler error. I don't have the time or desire to put that much work into a free open source app, especially without a ton of users. Fortunately, Xcode still supports building with Swift version 4.2, but we know that support for Swift 4 will eventually be removed from Xcode, as has support for Swift versions 1, 2, and 3. I did file a bug with the Swift project in 2018 about my issue, which was only a compiler warning in Swift 4, becoming a compiler error in Swift 5. However, the bug was immediately closed as "Won't Do", so the Swift team is apparently not interested in preserving backward compatibility. Whereas with Objective-C, the backward compatibility situation is mostly wonderful. Recently I took an open source Objective-C project last updated in 2006, in the ppc/i386 era, and all it took was a few build setting modifications to recompile for Apple silicon. It Just Works™!

(Aside: In fairness, the Objective-C Garbage Collection situation was a dumpster fire. Apple removed GC entirely from Mac OS X, killing all apps that used it. This was after certain Apple evangelists who shall remain nameless pushed Objective-C GC zealously. I never jumped on the GC bandwagon myself, but some developers did, to the detriment of themselves and their users. The removal of GC was one of the worst violations of backward compatibility in Objective-C history. Fortunately, it was the exception, not the norm.)

Another major issue I had with Swift was that I found bridging of objects between a Swift app and the Objective-C Apple frameworks to be very problematic. For example, Swift String and Objective-C NSString have different criteria for equality: Unicode canonical equivalence for the former, UTF-16 code unit sequence for the latter. Moreover, both Swift Dictionary and Objective-C NSDictionary frequently use strings for dictionary keys. This can produce unexpected results and bugs when you bridge String/NSString and Dictionary/NSDictionary, a common occurrence in AppKit and UIKit Swift apps. Add UserDefaults/NSUserDefaults to the mix, and it's a minefield. I'm not sure how you're even supposed to "code defensively" for this situation, because it's an inherent "feature" of the language bridge.

This reminds me of a saying we used to have as Cocoa developers: "Don't fight the frameworks." The API tend to be opinionated, as it were, and if you go against those opinions in your code, you're likely signing up for a lot of pain, frustration, and failure. I think the saying is relevant here, because most of Apple's frameworks were written in and for Objective-C. Swift was tacked on much later, and the design goals of Swift and Cocoa were not the same, sometimes in conflict. I usually try to avoid fighting the frameworks. (Occasionally I fight the frameworks on purpose, but you have to know the rules before you know when to break them.) I find the best programming language to be the language of the API: Objective-C for Cocoa, C for Core Foundation, JavaScript for DOM, etc. Of course Swift would be the best (only?) language to use for SwiftUI apps. Whether you should use SwiftUI at all is another matter, especially on Mac, but if you do, don't fight the framework in that case either. Unless and until SwiftUI replaces AppKit/UIKit for me, I'm not going to fight those Objective-C frameworks too much.

Let's talk about "safety" now. I don't see how I'm sacrificing safety by continuing to write Objective-C. I do ship my fair share of bugs, as you can see in the release notes of my software, but I almost never ship bugs that would have been detected by the Swift compiler. (Indeed a lot of mine are JavaScript bugs.) As an Objective-C expert, and a careful programmer in general, I simply don't write those kind of bugs anymore. Your Mileage May Vary, but my mileage is very good. I haven't shipped a crasher in years: I can't even remember the last one, it's been so long. It's important to recognize that the days of retain-release-autorelease memory management in Objective-C are long gone. Automatic Reference Counting makes memory management easier and eliminates the possibility of bugs in many cases. The Objective-C tooling has also improved significantly: we have more compiler warnings (if desired), nullability annotations (if desired), lightweight generics (if desired), the static analyzer, and runtime sanitizers. The baseline of Objective-C is much safer now than in the past. I didn't have a lot of trouble personally with retain-release-autorelease once I learned it, and my code has always been solid in that respect, but I do appreciate not having to make the effort anymore. I'm happy to take help from the compiler, as long as the compiler remains a help and doesn't become a hindrance. Despite the fact that Objective-C allows you to shoot yourself in the foot if you really insist, it also allows you to be quite safe if you really insist. The compiler won't complain if you declare every variable as generic id and always skip nil checking; complaining about that is really the job of your coworkers in code review.

What else do I prefer about Objective-C over Swift?

  1. Everything compiles faster, often much faster.
  2. The compiler doesn't crash ever.
  3. The debugger actually works, most of the time.
    I see a lot of people claim that Objective-C programmers "fear change" or "fear learning", but I see a lot of programmers of all languages who fear the debugger or fear learning how to use the debugger. The debugger is great, it's your friend! In fairness, maybe the unreliability of the Swift debugger has trained people to fear it?
  4. Trivial C and C++ API and source code compatibility.
    This is a huge and overlooked Objective-C advantage. The world outside of Apple mostly doesn't speak Swift.
  5. Header files.
    Wait, what?!? Yes, I prefer having header files to not having header files. A lot of programmers complain about maintaining header files, but header files represent your API, so you're complaining about maintaining an API, which is not a good look, to be honest. If there's no distinction between your interface and your implementation, then your architecture is likely not great.
  6. Verbosity.
    Wait, what?!? Yes, I prefer the verbosity of Objective-C method names. I find that it makes the code more readable and understandable. It almost kind of reads like English sentences. IMO Swift is too terse for its own good. Furthermore, I'm not afraid of typing or of boilerplate. Boilerplate code is the easiest code to write! For me, the time spent typing the code doesn't amount to a significant drain on my overall development time. I spend a lot of time thinking about the code, thinking about the user interface, thinking about the workflow and design of the app. (And thinking about how to sell the app.) It's the thought that counts, right? Premature optimization is the root of all evil, and I consider optimizing for number of characters typed in the code to be very premature, and thus very evil. ;-)

One more thing I'll discuss. Is Swift easier to learn than Objective-C? I don't know. Maybe, maybe not. I'm skeptical. Perhaps it's easier to get started in Swift, but I personally think it's harder to master Swift than to master Objective-C. It feels like there's a lot more complexity to Swift, once you get beyond the basics. Regardless, I learned C by reading the classic "C Programming Language" by Kernighan and Ritchie, and I learned Objective-C by reading Apple's own "Objective-C Programming Language" in their online developer documentation (archive, sigh). At the time, I didn't think in terms of "easy" or "hard". I wanted to learn how to write Mac software, so I had to learn Objective-C. There was no choice. I didn't pity myself for having to learn Objective-C, it was simply a technical requirement. Every programmer who wrote native Mac OS X and iOS apps prior to 2014 had to learn Objective-C, and it was fine! Countless great apps were written in Objective-C. The operating systems themselves were written in Objective-C. It didn't feel like a burden to me at the time, and it still doesn't feel like a burden to me.

Professional programmers will typically learn many programming languages over their careers, and in my experience, they're all approximately the same level of difficulty to learn. Each of them can be learned with several months of full-time use, give or take. I don't see a massive difference between the languages. There's a learning curve at the beginning, then eventually you make it over the hump, and you spend a lot more time in the learned state than you do in the learning state, so the initial cost is easily paid back if you stick with the language.

What about non-professionals though? As I mentioned before, perhaps it's easier for amateurs to get started with Swift than with Objective-C. (I also think that some Swift fanatics have engaged in slanderous scaremongering about Objective-C. IMO it's at worst only superficially scary, not really something to be scared of. Brackets are like a nice warm hug for your code! The scariest thing is actually code signing.) Does Swift help to bring potential programmers into the field? I don't know. My question, however, is this: why do beginners and professionals need to use the same programming language? If we have to "dumb down" all of our development tools just to appeal to beginners, that seems like a shame and waste to me. I'm not against beginners entering the field — we were all beginners at some point — but my first programming language ever wasn't Objective-C, it was Applesoft BASIC! I don't consider either Objective-C or Swift to be a good language for absolute beginners. Why don't we have dedicated beginner-friendly languages to bring people into programming, and then they can eventually and naturally move on to other languages if they decide to become professionals? Anecdotally, I didn't become a professional programmer until I learned Objective-C, and the language didn't stop me. The only thing we have to fear is fear itself! And JavaScript.

In 2007, programmers rushed en masse to iPhone because they were attracted by the platform, not by the language. Just as I was attracted by the Mac platform, not by the language. If the "selling point" of Apple development today is not the platforms but rather the programming language, if Swift is how you recruit programmers to the platform, that's actually a sad commentary on the state of the platforms, in my opinion. I feel that the crap store lockdown and race to the bottom have drained much of the enthusiasm out of our industry, and left us in a state where we think the programming language is the most exciting thing in the world.

Jeff Johnson (My apps, PayPal.Me)