If you develop for Apple platforms and use a third-party testing framework, you are very likely using Quick and Nimble. Otherwise, you have probably at least heard of them. I don’t use any third-party testing frameworks in my personal projects, but I have worked on teams that do. And I currently work on a team that uses Quick and Nimble, which is why it was important for me to get a recent critical bug fixed in Quick.
If you are using fastlane to automate your release process, you might be using the
increment_build_number actions to bump your version and build numbers, respectively. However, if your Xcode project is configured to use
xcconfig files, then you are out of luck. Shockingly, fastlane does not seem to support projects that use
xcconfig files and there is a surprising dearth of information online about how to make fastlane work with Xcode build configuration files.
I previously wrote about writing a custom shell command to quickly switch between Xcodes. But recently, I needed to determine the version of Swift that is bundled with Xcode — specifically the version of Swift that is shipping with the current Xcode 13.3 beta. I was pretty sure that it is Swift 5.6, but I wanted to know for certain.
In Swift there are 13 numeric types. Like most other programming languages, Swift provides signed integers of various sizes, corresponding unsigned integers, and a few floating-point types. But if you’ve been developing apps for Apple platforms for any amount of time, you’ll recognize another numeric type —
NSDecimalNumber). When we build the model layer of an app, it’s important to choose the right type for the task we want to accomplish. For example, if we are counting ticket sales for an event, then
Int (or possibly
UInt) would be the most appropriate type. But if we are calculating sales tax, then we’ll need to use a floating-point type. You likely know that
Double is more precise than
Float, but what about
Decimal? When should you reach for
A recent post from Tom Harrington explores the issues with optional and non-optional values in Core Data regarding how the framework interacts with Swift. It’s a good overview. You should read it. The post shares some workarounds to improve the situation, but I want to share how I solve these issues in a more robust way.
Speaking of drunk software and not being in service to our possessions, Screen Time on iOS and macOS has been shockingly buggy for me lately. It reports that I spent over 22 hours on my devices in a single day last week, and nearly 10 hours on another day this week. In both instances, a significant portion of the usage is supposedly occurring after midnight.
If you are working on a multiplatform SwiftUI project, you will start accumulating
#if os() checks and
#if canImport() checks. Overtime, these start to accumulate and — in addition to being unsightly — they make your code much more difficult to read. When possible, I have started to encapsulate these preprocessor directives to improve code organization and readability.
As of iOS 14 and macOS 11, you can define the entry-point and app lifecycle of your app in SwiftUI with the
App protocol instead of using the traditional
UIApplicationDelegate protocol from UIKit. However, SwiftUI is still missing the majority of APIs from UIKit. For any serious app, you’ll need to provide an app delegate.
This post started out as a “how to” for SwiftUI, but as I started testing and verifying I realized it is just an Xcode 13 bug. Historically, if you wanted to restrict your iOS app to specific device orientations, you would check or uncheck the various “Device Orientation” options in your project settings. You can find these by selecting your Xcode Project > App Target > “General” tab.
I’ve spent this past week diving into SwiftUI, seriously, for the first time. As you know, I’ve been keeping my eye on it since it was released, but I’ve avoided it due to a combination of hesitancy, apprehension, and just being too busy with other projects and work. However, while taking some time off from contracting work, I decided to dive in.
I’ve decided to deprecate one of my open source libraries, PresenterKit. The library has been in a sort of “maintenance mode” for awhile now. It never really became what I hoped and anticipated. I think it implemented some neat ideas and helped removed some boilerplate from UIKit, but I don’t think what it provided necessarily justified a library anymore — at least not given the lack of activity around the project.
I discovered a bug in Xcode 13 where tests crash for framework projects, preventing unit tests from successfully running on CI. The issue is due to some obscure code signing or debugger error that did not occur on Xcode 12. Fortunately, I have found a workaround.
I came across a situation today where I needed to run an iOS test suite for a Swift Package. Previously, this required you to have an Xcode project but it no longer does.
In last week’s issue of iOS Dev Weekly, Dave linked to this tweet from Mohammad Azam, which linked to this StackOverflow post on resetting your app between UI tests by completely deleting it. It’s a very clever idea! This post offers an improved version of the code and some thoughts on when to use this.
Here in Oakland and the rest of the Bay Area, more and more restaurants, bars, venues, and various events are requiring that people show proof of vaccine before entering. (As it should be.) Thankfully, all businesses and events allow showing proof digitally rather than carrying around your physical COVID-19 Vaccination Record Card from the CDC. This means you can take a photo with your phone and present that instead of your singular paper copy. This is great, but the tediousness of tapping around my phone to find and display it has been annoying. So, I made an iOS shortcut to present it instantly.
After I wrote and released Foil, my library for implementing a property wrapper for
UserDefaults, one of the criticisms on Twitter was that a mechanism for observing such properties should have been included. I disagreed. In the post I argued that this was easy enough for clients to handle on their own, but more importantly that there are too many options for how to do this and I didn’t think Foil should impose any one of them on clients.
I previously wrote about implementing Dark Mode in an older codebase, specifically how Dark Mode works (or doesn’t) with
CGColor. I recently fixed a bug in the same project that was difficult to track down because it manifested in such a strange way. After finding the problematic code, I realized that it is an extremely common scenario in iOS codebases — so you might have this bug in your code as well!
I was recently working on a project that uses modern collection views on iOS — that is, using diffable data sources, snapshots, and cell providers. I hooked up all the components and my collection view was working, or so I thought. I started to notice some very odd, unpredictable behavior when the collection view was updated. Some of the time, the cells were updated correctly. Other times, I would see duplicates and missing data. Here’s what went wrong.
This year at WWDC, some significant improvements and changes were announced for
UITableView. You can watch 10252: Make blazing fast lists and collection views for all the details, but I want to highlight some of them here.
I’ve been following what’s going on with SwiftUI since it was released with iOS 13 at WWDC 2019 and have even taken extensive notes, but I have avoided using it. As I wrote before, I mainly wanted to avoid dealing with bugs and workarounds that might make me less productive compared to using UIKit, which I know quite well. I’m very interested in learning and using it, I’m just hesitant given some of Apple’s history, like early years of Swift. I have no doubt that SwiftUI will be the future of Apple platform development, the question is when that future will arrive. This year the framework is debuting its third major release in iOS 15. How far has SwiftUI come, and is it ready for building serious apps?
A few months ago, I shared my notes and resources for learning about compilers and LLVM. It turned out to be pretty popular and folks seemed to find it useful. So I decided to do it again, but this time for SwiftUI. However, unlike learning about compilers and LLVM, I am not declaring bankruptcy with learning SwiftUI. While I have still not written a single line of SwiftUI code, I know I eventually will.
Lately, it feels like every few days someone is sharing a new Xcode tip on Twitter or on their blog. They range from hidden settings to features I simply never knew about. I started saving links and planned to add a new “Xcode tips” section to my TIL repo on GitHub to reference later. But as I started, I realized that the resulting markdown file would not be easily discoverable or shareable. I thought, wouldn’t it be nice if the iOS and macOS developer community had a single place to find and share Xcode tips?
Xcode’s UI testing framework has had its ups and downs over the years. Most recently, it has been much more robust and reliable in my experience. However, tests still tend to flake sometimes. Here are some ways that I have been able to reduce flakiness in UI tests.
I was never a fan of failable initializers in Swift. I do not think this is the correct place to fail and return
nil most of the time. Of course, there are exceptions where a failable initializer is appropriate. But there is another behavior of which to be aware. When constructing a class via a failable initializer,
init?() — or a throwing initializer,
init() throws — the deinitializer,
deinit, is not called if initialization fails or throws, respectively.
You know, the thing that is actually most disheartening, disappointing, frustrating, and plainly sad about Apple’s surprise announcement today is that we will not receive any sort of response to our collective dismay. There will be no public acknowledgment, much less an apology (not that it would help much). Only silence.
Out of nowhere today, when I tried to run
pod install on my machine, it could not be found. Uh… what?
Xcode 12 was released and it includes a change to how tabs and navigation work. In Xcode 12, the tabs have their own tabs. It makes no sense to me. I know we are supposed to be nice to each other about software, but this new UI/UX is beyond incomprehensible. What made it worse is that this new “tabs within tabs” was the default setting (overriding preferences I had previously set) and I could not figure out how to restore the previous (desired) behavior.
The release notes for Xcode 12 beta state that the release “supports on-device debugging for iOS 9 and later, tvOS 9 and later, and watchOS 2 and later.” I am not sure if that means support for building and deploying for iOS 8 is completely removed, but it sounds like it. Who is still deploying to iOS 8, anyway?
While debugging some code the other day, I wanted to verify the behavior of global variables and static members in Swift. I vaguely remembered from the early days of Swift, that
static let members and global constants were atomic and computed lazily — one of the many improvements over Objective-C.
I try to have only one Xcode installed at a time for simplicity and tidiness. But such a setup is rare as we often must manage stable releases and beta versions simultaneously.
I few months ago I wrote a script to override status bar display settings in the iOS simulator using the new
simctl status_bar feature in Xcode 11. This was great, but it still required that you manually run the script after launching simulators. This was not ideal, as Dave pointed out in iOS Dev Weekly when he challenged me to automate this anytime a simulator launches.
For an iOS project that I am currently working on, I am implementing Dark Mode. The codebase is approaching 7 years old, it is mostly Swift with some legacy Objective-C, and it currently supports iOS 11 and above. Aside from the tedium of ensuring the updated colors are being used throughout the codebase, I expected this task to be straight-forward. However, there were some unanticipated issues.
Last year Xcode 11 was released with integrated support for the Swift Package Manager. For a couple of small projects of mine, I decided to try using it to manage dependencies instead of CocoaPods. Overall, using SwiftPM was a great user experience, but (as expected) it has clear shortcomings due to its lack of maturity.
Xcode has a great UI for setting and editing breakpoints. I use breakpoints all the time while working and debugging, but I want to share another, unconventional way that I use them.
I recently needed to determine when the user has manually switched between dark mode and light mode on macOS. In my menu bar app, Lucifer, the icon reflects the current appearance setting when you change it from the app — an inverted pentagram for dark mode and an upright pentagram for light mode. But there’s a bug. If the user manually changes the appearance setting from System Preferences, or if they are using the new “auto” setting in macOS Catalina, the icon gets stuck in its previous state.
Unfortunately, iCloud does not have a good reputation for being reliable, especially during beta releases of iOS and macOS. Yet a lot people still use it, often without any problems. I still use it, despite a few bad experiences in the past, because the best alternatives are questionable for other reasons. I’ve had good luck with iCloud Drive for the past few years, but I am terrified and paranoid of getting caught in the middle of an iCloud clusterfuck, so I backup what I have in iCloud periodically using
With version 11 of Xcode, the IDE ships with a new feature in the
simctl tool that can override status bar values for iOS simulators. This allows you to take better screenshots for the App Store without having to worrying about the time, battery level, etc. It is a great improvement, but there are some significant shortcomings. I’ve written a script to fix at least some of those.
The other day I was debugging a crash in a UI test for an open pull request at work. The bug turned out to be extremely subtle and difficult to notice. I spent way too much time staring at the changes, trying to understand what was wrong. Let’s see if you can spot the error.
When you file a radar for a bug on one of Apple’s platforms, you should (usually) always attach a sysdiagnose. A sysdiagnose provides a lot of helpful information for the person who is trying to understand how the bug happened. Amongst other things, it contains logs from various parts of the OS, and all recent crash logs. Without it, the person on the other end of your report inside Apple may not be of much help. On macOS running sysdiagnose is somewhat common, but what about iOS?
PlanGrid is a productivity app for construction fieldworkers. The easiest way to explain it to software developers is that it’s like an IDE, Git, and GitHub or JIRA — but for construction. Think of all the amazing software tools we have to do our jobs as programmers. The equivalent tools for construction simply did not exist before PlanGrid, and they still have a lot of room to grow.
As software developers, we build software for specific purposes. We anticipate that people will use an app in certain ways. Yet, we often discover that users are behaving differently than we expected. They hack a custom, “unsupported” workflow to workaround an app’s unintended limitations. Once we realize this, we have the power to turn these user workarounds into first-class features. However, sometimes we find that our apps are being used in totally different, unimaginable ways.
At PlanGrid, we recently discovered that the app was being used as a digital archaeological tool.
The Swift type-checker remains a performance bottleneck for compile times, though it has improved tremendously over the past two years. You could even say the type-checker has gone from being drunk to sober. To help users debug these issues, awhile back Jordan Rose added a frontend Swift compiler flag that would emit warnings in Xcode for functions that took too long to compile, or rather took too long to type-check. In Xcode 9, there’s a new, similar flag for checking expressions.
Beginning immediately, JSQMessagesViewController is no longer officially supported or maintained. In fact, you may have noticed that it has been neglected for the past year. The most recent release was published almost exactly one year ago today. This is an incredibly difficult post for me to write and I have not made this decision carelessly. This open source project had a great run. There was (and still is) a great community around it, and I’m sorry for bringing this to an end.
In software development, singletons are widely discouraged and frowned upon — but with good reason. They are difficult or impossible to test, and they entangle your codebase when used implicitly in other classes, making code reuse difficult. Most of the time, a singleton amounts to nothing more than a disguise for global, mutable state. Everyone knows at least knows that is a terrible idea. However, singletons are occasionally an unavoidable and necessary evil. How can we incorporate them into our code in a clean, modular, and testable way?
As developers, we’ve been lamenting the continued existence of the inferior A5 system-on-a-chip for the past couple of years. Both iOS 8 and iOS 9 continued to support iPhone 4S, iPad 2, and iPad Mini 1 — devices that struggled to run the OS itself. I had hoped that iOS 9 would finally drop support for these less powerful devices, but it didn’t. Today, we can finally say goodbye to the A5. Well, almost.
Do you love writing code? Are you passionate about open source? Do you want to get more involved, but have yet to find a project to which you want contribute? Are you interested in contributing to a widely used, impactful project? Then I have a proposition for you! I am looking for dedicated core contributors to help maintain JSQMessagesViewController!
In iOS development, the core of nearly every app rests on the foundations provided by
UITableView. These APIs make it simple to build interfaces that display the data in our app, and allow us to easily interact with those data. Because they are so frequently used, it makes sense to optimize and refine how we use them — to reduce the boilerplate involved in setting them up, to make them testable, and more. With Swift, we have new ways with which we can approach these APIs and reimagine how we use them to build apps.
Mike Ash has a great Friday Q&A on namespaced constants and functions in C. It is a powerful and elegant technique to avoid using
#define and verbose Objective-C prefixes. Although Swift types are namespaced by their module, we can still benefit from implementing this pattern with
enum types. I’ve been experimenting with this approach for constants in Swift and it has been incredibly useful.
I recently gave a talk at the Swift Language User Group (#SLUG) meetup at Realm in San Francisco. A video of the talk is now online over at Realm’s blog, where it is synced up with my slides. If you haven’t already seen it, go check it out! Realm does an absolutely amazing job with posting these meetup talks — in addition to the video and slides, there’s a full transcript and subtitles.
In a previous post, I discussed how Swift’s failable initializers could be problematic. Specifically, I argued that their ease of use could persuade or encourage us to revert to old (bad) Objective-C habits of returning
init. Initialization is usually not the right place to fail. We should aim to avoid optionals as much as possible to reduce having to handle this absence of values. Recently, @danielgomezrico asked a great question about a possible use case for a failable initializer — parsing JSON. Given this problem’s popularity in the Swift community, I thought sharing my response here would be helpful.
The observer pattern is a powerful way to decouple the sending and handling of events between objects in a system. On iOS, one implementation of this pattern is via NSNotificationCenter. However, the
NSNotificationCenter APIs are kind of cumbersome to use and require some boilerplate code. Luckily, Swift gives us the tools to improve
NSNotificationCenter with very little code.
As I continue my work with Core Data and Swift, I have been trying to find ways to make Core Data better. Among my goals are clarity and safety, specifically regarding types. Luckily, we can harness Swift’s optionals, enums, and other features to make managed objects more robust and more clear. But even with the improvements that Swift brings, there are still some drawbacks and limitations with Xcode’s current toolset.
Core Data is probably loved as much as it is shunned by iOS developers. It is a framework of great power that often comes with great frustration. But it remains a popular tool among developers despite its pitfalls — likely because Apple continues to invest in it and encourages its adoption, as well as the availability of the many open-source libraries that make Core Data easier to use. Consider unit testing, and Core Data gets a bit more cumbersome. Luckily, there are established techniques to facilitate testing your models. Add Swift to this equation, and the learning curve gets slightly steeper.
A few weeks ago I published the sixth major release of
my our messages UI library for iOS. This release closes the door on a major milestone for this project, so I wanted to take the time to highlight its significance, discuss its new features, and examine its design. Of course, this would not have been possible without our amazing open-source community and the contributors to this project.
Swift is still young and ever-changing. With each release, we have seen dozens of tweaks, additions, and deletions. And there is no reason for us to think that this rapid evolution will decline anytime soon. To remind us of exactly that, the latest post on Apple’s Swift Developer Blog introduces a new feature in Swift 1.1 in Xcode 6.1 — failable initializers.
When the App Store launched, there was one iPhone with one screen size and one pixel density. Designing your user interfaces was relatively simple and the technical debt of hard-coding them was cheap. Today, developers and designers face many challenges in creating apps that must work on dozens of different devices. Long gone are the days of 480x320. We can no longer depend on physical screen sizes and must always be prepared for the next generation of devices.