Developing high-quality iOS apps gets more difficult every year. The expectations of our users are ever-increasing, and the breadth and complexity of UIKit's APIs are ever-expanding. Thankfully, there's been a marked increase in the number and quality of new technologies that aim to simplify app development. New database technologies like Realm and Couchbase Mobile, as well as more venerable technologies like Core Data and UserDefaults, are intended to make it easier to save user data locally and to the Cloud. Additionally, ReactiveSwift and RxSwift aim to fundamentally change the way we architect our apps by allowing us to update our UI automatically in response to user actions and data model changes. Combining these technologies can dramatically simplify app development…but only after investing a lot of time in learning the frameworks themselves and the theories behind them.
I've used some, but not all, of the above technologies, and, for the most part, I really liked them. I encourage everyone to try them out for himself or herself. However, personally, I prefer to limit the number of dependencies I add to the software I write. If possible, I limit my dependencies to only software that ships with iOS and macOS. Of course, until the new, fabled declarative (and, hopefully, reactive) UI framework debuts for iOS in 2019, limiting dependencies to UIKit and friends means that we lose the benefits of the modern persistence and reactive technologies listed above, right?
Core Data provides some of these benefits, but I dislike it because of its unwieldy API and the inherent mutability of its model objects. UserDefaults also provides the ability to save its data in iCloud and to be notified when its data changes, but UserDefaults is not intended to be used as a general persistence engine. However, there is one technology that I haven't mentioned yet. In the new app/service I'm writing with my coworker Nathan Herald, we decided to rely on the venerable, battle-tested SQLite to power the new, modern apps we're building. In the next few posts, I'm going to explain how we used the built-in features of SQLite to easily add simple persistence and reactivity to our new apps. The next few blog posts will cover the following topics:
- Building a lightweight SQLite wrapper in Swift
- Encoding and decoding SQLite in Swift
- Reacting to changes to data in the SQLite database
Nathan and I built a small example iOS Slack client to illustrate how the strategies we describe can be used to power a modern, moderately-complex app. We'll be open-sourcing everything we talk about as we go along, but the purpose of this series is not to release another SQLite Swift wrapper into the wild (if that's what you're looking for, check out GRDB or SQLite.swift). Instead, my hope is to show how easy it is to build modern apps using only the technology that ships with iOS.