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.
Updated: 30 Sep 2019
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
Updated: 28 Sep 2019
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.
Updated: 05 Jan 2019
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.
Updated: 18 Jul 2017
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.
Updated: 23 Jul 2015
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.