Ultimate Portfolio App
Learn to build one complete app using SwiftUI, Core Data, CloudKit, StoreKit, Widgets, Spotlight, and more.
Part 1: Building the core app
The first step of our project will be to build the core of the app itself, providing all the fundamental features. Everyone needs to follow these steps.
While I’m sure you’re keen to get started programming immediately, please give me a few minutes to outline the goals of this course and explain why it’s different from other courses I’ve written.
Setting up the basics
Almost always, the key to getting a great app is getting a great data model – deciding as early as you can what data you want to store, and how each piece relates to other pieces. So, we’re going to dive straight into Core Data!
Now that we have our basic data model configured and coded, we can put it to use by building a simple user interface to help make sure our data is in place and working correctly.
At this point we have something very simple working, so now is a great time to stash your code away somewhere safe using source control. If you already know how to use Git then you’re welcome to skip this part.
Core Data’s optionals are quite different from Swift’s optionals, which makes them a little uncomfortable to work with. In this article I’m going to show you two ways of fixing this, which will help clear up our code nicely.
Although apps can live in the background for quite a while, eventually they will be terminated. But when a user relaunches them, it’s a good idea to bring them roughly back to where they were, and with state restoration we can do just that.
Editing our data
Our next step is to build a simple form so the user can edit items, which in itself isn’t too hard. However, along the way I want to show you some useful tips for tracking changes and updating the UI – it’s not quite as straightforward as you might expect.
Rather than calling
update() when our view disappears, what we really want to do is update the object before the disappear happens. In this article I’ll show you the SwiftUI native way of doing this, then walk you through an alternative that I prefer.
Now that item editing works well, we can add a screen to edit projects. But before we can even think about that we need to add a custom section header to let users select a project to edit.
10. Editing projects
Editing projects is much like editing items, but because a good portfolio project should show off a range of skills we’re going to bring in grids, alerts, tap gestures, and more.
As folks have worked their way through the series so far, they’ve sent in various questions about implementation choices and more. In this article I want to address the eight most common questions asked so far, so that everyone can benefit.
Filling out the functionality
At this point you can get a basic idea for the UI of our app, but it has a fatal flaw: although we can add test data, we can’t do the same for user data. Let’s fix that now – there’s more to it than you might think!
Our default sort for project items works well enough, but with a little extra work we can let users choose how to sort them. In this article I’m going to walk you through several different ways of approaching this problem, some that I think work well, and others not so much…
At this point our main list view is almost done, but before we’re finished we’re going to add some icons, make landscape mode work better, and even fix a rather nasty deletion bug.
Parsing data into your app is the single most common task any iOS developer needs to do, so in this article we’ll start to build out an Awards tab using JSON.
Now that we’ve designed a basic awards UI, we can bring it to life with some Core Data queries to determine which awards have actually been earned.
So far our home view has simply been a host for adding test data, but that changes now: we’re going to make the home view a summary of all their project progress, plus the most important items coming up next.
Beginning the clean up
Everything we’ve done so far has produced a serviceable app, although it does have a few bugs that we’ll address later. But before we address those, I want to change gear and focus on making our existing code better. This is where the real work begins!
Our app was designed to work in English, and although you might not want to change that your should at least be able to change. Let’s start with that…
It is my firm belief that every iOS app should be usable to everyone, and putting in the work to make your app function well no matter who is using it says a lot about the kind of developer you are.
Although our SwiftUI layouts conform to the View protocol, if you were to try to think about them in MVC terms I’d say they were more like controllers. And like controllers from UIKit, we need to put in some work to keep SwiftUI views lean – let’s look at this now…
I’ve had a whole bunch more questions sent in from readers, covering Core Data, property wrappers, localization, and more, so let’s dive into them with some code examples.
One of the least obvious but most important clean ups lies in our use of Core Data, because right now we’re leaking data and also showing flat out wrong data. To fix these we need to use some more advanced Core Data, so let’s get into it…
24. Linting our code
Code is designed to be read far more often than it is written, and one of the simplest ways of making code easier to read is to make it uniform – to make sure your code follows a simple style, so your brain can focus less on spacing and naming and more on understanding how the code actually works.
Good documentation describes not only what code does, but provides context on why it works a certain way, what assumptions you made, any optimizations you made, as well as describing subtleties in the implementation if you’re dealing with difficult code. In this article we’re going to be documenting our project for other developers and beyond!
We have one last easy task before we look at something trickier, which is to organize the Xcode project itself. Here I’m going to show you two different approaches so you can contrast them yourself, then explain which I prefer and why.
Testing our project
At last it’s time to start writing tests for our project, which means a little bit of setup work backed by writing our first couple of tests – we’ll take this slow initially, but lay down a good foundation for future tests.
Our app relies extensively on user data, so if there’s one part of it that absolutely must be bullet proof it’s our Core Data stack. In this article we’ll explore writing tests for our data, including projects, items, and awards.
In previous tests we relied upon our sample data creating 5 projects and 50 items, but that isn’t set in stone right now – it’s an implementation detail, meaning that it’s a behavior that happens to be the case but isn’t explicitly guaranteed. This is a common cause of bugs, so in this article we’re going to write tests for our development code, and along the way discover and resolve some interesting quirks…
Our project has three extensions that add functionality to Apple’s own code, and we need to treat these carefully – we don’t own them, so their behavior might change at any point in the future. So, in this article we’re going to write tests for the extensions we created, making sure they work correctly every time.
Although our project doesn’t do anything particularly performance intensive, having a great portfolio app means you should at least attempt to demonstrate you understand how performance tests work. In this chapter we’ll add just such a test to our project, to make sure our award counting work is fast.
Even after writing stacks of unit tests, chances are your test coverage is still well below 40%. Those units tests are really important, but if you really want great test coverage you need to add some UI tests and that’s exactly what we’re going to work on here.
Part 2: Integrating with the system
Once our core app is built, we can explore optional extras such as integrating with StoreKit, Apple Pay, and more. These steps are optional and you can follow any of them in any order you want.
Part 3: Going cross-platform
The final step of our project will be to see how we can take our code to macOS, tvOS, and even watchOS.